8

このようなデータを含む列があります。ダッシュは同じ請求書の複数のコピーを示し、これらは昇順でソートする必要があります

790711
790109-1
790109-11
790109-2

この番号で昇順にソートする必要がありますが、これは varchar フィールドであるため、このようにアルファベット順にソートされます

790109-1
790109-11
790109-2
790711

これを修正するために、-(ダッシュ)を空に置き換えてから、それを数値としてキャストしてから並べ替えてみました

select cast(replace(invoiceid,'-','') as decimal) as invoiceSort...............order by invoiceSort asc

これはより良く、このように並べ替えますが

            invoiceSort
790711      (790711)   <-----this is wrong now as it should come later than 790109
790109-1    (7901091)
790109-2    (7901092)
790109-11   (79010911)

- (ダッシュ) で請求書 ID を分割し、2 つの分割部分で注文することを誰かが提案してくれました

いいね=====> order by split1 asc,split2 asc (790109,1)

これはうまくいくと思いますが、列をどのように分割しますか。

インターネット上のさまざまな分割関数はテーブルを返すものですが、この場合はスカラー関数が必要になります。

使用できる他のアプローチはありますか?データはグリッド ビューで表示され、グリッド ビューはデフォルトで 2 列での並べ替えをサポートしていません (ただし、実装できます:))。

編集:すべての回答に感謝します。すべての答えは正しいですが、SQLクエリのリファクタリングを最小限に抑えて、これらの列をGridViewソートに組み込むことができる答えを選択しました。

4

9 に答える 9

4

REVERSECHARINDEX、およびを賢明に使用すると、SUBSTRING必要なものが得られます。以下のコードでは、何が起こっているのかを説明するために、うまく説明できる列名を使用しています。

サンプル データを設定します。

DECLARE @Invoice TABLE (
    InvoiceNumber nvarchar(10)
);

INSERT @Invoice VALUES
('790711')
,('790709-1')
,('790709-11')
,('790709-21')
,('790709-212')
,('790709-2')

SELECT * FROM @Invoice

サンプルデータ:

InvoiceNumber
-------------
790711
790709-1
790709-11
790709-21
790709-212
790709-2

そして、これがコードです。最終的な式が単純化されるのではないかとしつこく感じています。

SELECT 
    InvoiceNumber
    ,REVERSE(InvoiceNumber) 
        AS Reversed
    ,CHARINDEX('-',REVERSE(InvoiceNumber)) 
        AS HyphenIndexWithinReversed
    ,SUBSTRING(REVERSE(InvoiceNumber),1+CHARINDEX('-',REVERSE(InvoiceNumber)),LEN(InvoiceNumber)) 
        AS ReversedWithoutAffix
    ,SUBSTRING(InvoiceNumber,1+LEN(SUBSTRING(REVERSE(InvoiceNumber),1+CHARINDEX('-',REVERSE(InvoiceNumber)),LEN(InvoiceNumber))),LEN(InvoiceNumber)) 
        AS AffixIncludingHyphen
    ,SUBSTRING(InvoiceNumber,2+LEN(SUBSTRING(REVERSE(InvoiceNumber),1+CHARINDEX('-',REVERSE(InvoiceNumber)),LEN(InvoiceNumber))),LEN(InvoiceNumber)) 
        AS AffixExcludingHyphen
    ,CAST(
        SUBSTRING(InvoiceNumber,2+LEN(SUBSTRING(REVERSE(InvoiceNumber),1+CHARINDEX('-',REVERSE(InvoiceNumber)),LEN(InvoiceNumber))),LEN(InvoiceNumber))
        AS int)  
        AS AffixAsInt
    ,REVERSE(SUBSTRING(REVERSE(InvoiceNumber),1+CHARINDEX('-',REVERSE(InvoiceNumber)),LEN(InvoiceNumber))) 
        AS WithoutAffix
FROM @Invoice
ORDER BY
    -- WithoutAffix
    REVERSE(SUBSTRING(REVERSE(InvoiceNumber),1+CHARINDEX('-',REVERSE(InvoiceNumber)),LEN(InvoiceNumber))) 
    -- AffixAsInt
    ,CAST(
        SUBSTRING(InvoiceNumber,2+LEN(SUBSTRING(REVERSE(InvoiceNumber),1+CHARINDEX('-',REVERSE(InvoiceNumber)),LEN(InvoiceNumber))),LEN(InvoiceNumber))
        AS int)

出力:

InvoiceNumber Reversed   HyphenIndexWithinReversed ReversedWithoutAffix AffixIncludingHyphen AffixExcludingHyphen AffixAsInt  WithoutAffix
------------- ---------- ------------------------- -------------------- -------------------- -------------------- ----------- ------------
790709-1      1-907097   2                         907097               -1                   1                    1           790709
790709-2      2-907097   2                         907097               -2                   2                    2           790709
790709-11     11-907097  3                         907097               -11                  11                   11          790709
790709-21     12-907097  3                         907097               -21                  21                   21          790709
790709-212    212-907097 4                         907097               -212                 212                  212         790709
790711        117097     0                         117097                                                         0           790711

実際に必要なのはORDER BY節だけであることに注意してください。残りは私の作業を示すだけです。これは次のようになります。

  • 文字列を反転し、ハイフンを見つけ、ハイフンの後の部分文字列を取得し、その部分を逆にします。これは接辞のない数字です
  • (接辞のない数字) の長さは、ハイフンを含む接辞を取得するために最初から何文字削除する必要があるかを示します。追加の文字をドロップして数値部分だけを取得し、これを に変換しintます。幸いなことに、この変換では空の文字列がゼロになるという点で、SQL Server とは一線を画しています。
  • 最後に、これら 2 つのピースを取得したら、ORDER BY(接辞のない数値) を単純化し、次に (接辞の数値) を使用します。これが私たちが求める最終的な注文です。

SUBSTRING(value, start)SQL Serverがその時点から始まる文字列を取得することを許可していれば、コードはより簡潔になりますが、そうではないためSUBSTRING(value, start, LEN(value))、多くのことを言わなければなりません。

于 2013-06-06T09:36:05.460 に答える
2

各パーツを個別に注文するのが最も簡単で信頼できる方法ですが、他の方法を探す必要はありません。この単純なクエリを見てください。

select *
from Invoice
order by Convert(int, SUBSTRING(invoiceid, 0, CHARINDEX('-',invoiceid+'-'))) asc,
         Convert(int, SUBSTRING(invoiceid, CHARINDEX('-',invoiceid)+1, LEN(invoiceid)-CHARINDEX('-',invoiceid))) asc
于 2013-06-09T06:18:09.323 に答える
2

ここにはたくさんの良い答えがありますが、これは効果的な句による最もコンパクトな順序かもしれないと思います:

SELECT *
FROM Invoice
ORDER BY LEFT(InvoiceId,CHARINDEX('-',InvoiceId+'-'))
         ,CAST(RIGHT(InvoiceId,CHARINDEX('-',REVERSE(InvoiceId)+'-'))AS INT)DESC

デモ: - SQL フィドル

ここにリストされているメソッドのいくつかは、サフィックスなしのバージョンをサフィックス付きのバージョンよりも小さいものとして扱っていないため、「790709」バージョンをテストに追加したことに注意してください。

InvoiceID の長さが「-」の前で異なる場合、次のものが必要になります。

SELECT *
FROM Invoice
ORDER BY CAST(LEFT(list,CHARINDEX('-',list+'-')-1)AS INT)
         ,CAST(RIGHT(InvoiceId,CHARINDEX('-',REVERSE(InvoiceId)+'-'))AS INT)DESC

ダッシュの前のさまざまな長さのデモ: SQL Fiddle

于 2013-06-09T18:33:55.420 に答える
1

並べ替えを 2 つのセクションに分割します。

SQL フィドル

MS SQL Server 2008 スキーマのセットアップ:

CREATE TABLE TestData
(
  data varchar(20)
)

INSERT TestData
SELECT '790711' as data
UNION
    SELECT '790109-1'
UNION
    SELECT '790109-11'
UNION 
    SELECT '790109-2'

クエリ 1 :

SELECT *
FROM TestData
ORDER BY 
    FLOOR(CAST(REPLACE(data, '-', '.') AS FLOAT)),
    CASE WHEN CHARINDEX('-', data) > 0 
        THEN CAST(RIGHT(data, len(data) - CHARINDEX('-', data)) AS INT)
        ELSE 0 
    END

結果

|      DATA |
-------------
|  790109-1 |
|  790109-2 |
| 790109-11 |
|    790711 |
于 2013-06-11T09:41:41.407 に答える
1

1 つの方法は、パーツに分割InvoiceIdしてから、パーツを並べ替えることです。ここでは派生テーブルを使用していますが、CTE または一時テーブルでも同様に実行できます。

select InvoiceId, InvoiceId1, InvoiceId2
from
(
    select
    InvoiceId,
    substring(InvoiceId, 0, charindex('-', InvoiceId, 0)) as InvoiceId1,
    substring(InvoiceId, charindex('-', InvoiceId, 0)+1, len(InvoiceId)) as InvoiceId2
    FROM Invoice
) tmp
order by
cast((case when len(InvoiceId1) > 0 then InvoiceId1 else InvoiceId2 end) as int),
cast((case when len(InvoiceId1) > 0 then InvoiceId2 else '0' end) as int)

上記のInvoiceId1InvoiceId2は の構成部品ですInvoiceId外側 にはパーツが含まれていますselectが、デモンストレーションのみを目的としており、select でこれを行う必要はありません。

派生テーブル (内部select) はInvoiceId、コンポーネント パーツと同様に を取得します。それが機能する方法は次のとおりです。

  • にダッシュがある場合、 にInvoiceIdInvoiceId1数字の最初の部分InvoiceId2が含まれ、2 番目の部分が含まれます。
  • ダッシュがない場合はInvoiceId1空になりInvoiceId2、数値全体が含まれます。

上記の 2 番目のケース (ダッシュなし) は最適ではありません。理想的InvoiceId1には数値を含み、InvoiceId2空になるからです。内部選択を最適に機能させると、選択の可読性が低下します。ソートを可能にするのに十分であるため、最適ではない、より読みやすいアプローチを選択しました。

これが、ORDER BY句が長さをテストする理由です。上記の 2 つのケースを処理する必要があります。

SQL Fiddleでのデモ

于 2013-06-06T14:34:09.730 に答える