2016-08-22 1 views
1

SQLでアパートメント番号のテーブルをソートする必要があります。よく知られていない人にとっては、これらは必ずしも数字ではありませんが、あたかもあたかもあたかもあたかも数字の順序付けが必要です。SQLでのアパート番号の並べ替え - 数値的辞書的順序付け

-たとえば、次のようにアパートの番号の可能なセットを注文することになりますないすべてのアパート - の数字が文字列でエンコードされた小数の整数であるため、

1 
10 
101 
101-A 
1000 
200 
200A 
2000 
C 
D 
E-100 
F 

ORDER BY CONVERT(int, ApartmentNumber)を行うと、動作しないでしょう。同様にORDER BY ApartmentNumberを実行すると、1000の後に101が配置されるため、機能しません。

StackOverflowの上の他のQAは、一般的に値Sorting string column containing numbers in SQL?やエラー処理と並べ替えを行うための既知の固定形式のいずれかで自分自身を懸念:私自身のプロジェクトでSorting field by numerical value and lexicographical value

、以前の開発者は、このトリックを使用:

ORDER BY 
    RIGHT('00000000000000000000' + RTRIM(ApartmentNumber), 20) ASC 

...さらに悪いと感じる...。何故なら、このトリックはアルゴリズム的には健全です。データベースエンジンに文字列割り当てを実行させるためのハッキングのような感じです(連結を最適化しない場合は複数回もあり、文字列操作にはRTRIM)。

別のアプローチは、上差し出さSOです:

ORDER BY 
    LEN(ApartmentNumber), 
    ApartmentNumber 

...しかし、これは入力セットのこの間違った順序が得られます。

1 
C 
D 
F 
10 
101 
200 
1000 
2000 
200A 
101-A 
E-100 

私は2008年にSQL Serverのローカルで2012を(使用しています(レベル100)互換モード)、このアプリケーションはAzure SQLサーバー(Azure SQL V12)にデプロイされます。

UPDATE:

私はいくつかの選択肢を検討してきた、私は「最高の」ではなくvarchar(10)の固定長char(10)フィールドを使用すると、フィールドの内容が常に左整列されていることを確実にするためだと思いますそうすれば並べ替え順序は簡単にORDER BY ApartmentNumberで保証されます。

更新2:上記の考え(char(10))は、2000の前にソートする必要がある200Aの問題を解決しません。私は最善の解決策は、均一な整数表現に値を正規化し、そのint値をデータベースに格納することだと思う。変換を行うアルゴリズムは、SQLで記述されていない場合(つまり、最も簡潔に)最適です。

+2

どのdbmsを使用していますか? –

+0

@vkp良いクロスプラットフォームソリューションがあることを期待していましたが、SQL Server 2012とSQL Azure V12をターゲットにしています。 – Dai

+0

おそらく、さまざまなフォーマットすべてにマッチする一連のマスクが必要です。 – shawnt00

答えて

0

単純なマスキングパターンを使用していた私の元の考えはうまくいくとは思っていませんでした。うまくいけば、あなたはそれでいくらかの価値を見つけることができます。

order by 
    case 
     when patindex('%[0-9][A-Z-]%', apt) > 0 
      then cast(substring(apt, 1, patindex('%[0-9][A-Z-]%', apt)) as int) 
     when patindex('[0-9]%', apt) = 1 
      then cast(apt as int) 
     else 99999 
    end /* numeric_prefix */, 
    case 
     when patindex('%[A-Z][0-9-]%', apt) > 0 
      then left(apt, patindex('%[A-Z][0-9-]%', apt)) 
     when patindex('[A-Z]%', apt) = 1 
      then apt 
     else '' 
    end /* char_prefix */, 
    case 
     when patindex('%[A-Z-][0-9]%', apt) > 0 
      then cast(substring(apt, patindex('%[A-Z-][0-9]%', apt) + 1, 10) as int) 
     else 0 
    end /* numeric_suffix */, 
    replace(apt, '-', '') /* stripped_hyphen */, 
    case when charindex('-', apt) = 0 then 0 else 1 end /* sort_hyphen_last */ 

http://rextester.com/MFYVN38156

ここでは、保存して並べ替えに使用することができ、単一の式です:

case 
    when patindex('%[0-9][A-Z-]%', apt) > 0 
    then right('*****' + left(apt, patindex('%[0-9][A-Z-]%', apt)), 5) + 
      right('>>>>>' + 
       replace(substring(apt, patindex('%[0-9][A-Z-]%', apt) + 1, 10), '-', ''), 5) 
    when patindex('%[A-Z][0-9-]%', apt) > 0 
    then right('>>>>>' + left(apt, patindex('%[A-Z][0-9-]%', apt)), 5) + 
      right('*****' + 
       replace(substring(apt, patindex('%[A-Z][0-9-]%', apt) + 1, 10), '-', ''), 5) 
    when patindex('[0-9]%', apt) = 1 then right('*****' + apt, 5) + '>>>>>' 
    when patindex('[A-Z]%', apt) = 1 then right('>>>>>' + apt, 5) + '*****' 
    else '>>>>>*****' 
end + 
case when charindex('-', apt) = 0 then '' else '-' end /* collate Latin1_General_BIN */ 

>は、数字とアルファベット文字の間でソート文字として選ばれました。 *は数字の前になります。出力は次のようになります。

apt  sort_string 
-------- ------------- 
    1  ****1>>>>> 
    10  ***10>>>>> 
    101  **101>>>>> 
    101-A **101>>>>A- 
    200  **200>>>>> 
    200A  **200>>>>A 
    200-A **200>>>>A- 
    1000  *1000>>>>> 
    2000  *2000>>>>> 
    C  >>>>C***** 
    D  >>>>D***** 
    E  >>>>E***** 
    E10  >>>>E***10 
    E100  >>>>E**100 
    E-100 >>>>E**100- 
    E101  >>>>E**101 
    E-101 >>>>E**101- 
    E200  >>>>E**200 
    E-200 >>>>E**200- 
    E1000 >>>>E*1000 
    E-1001 >>>>E*1001- 
    F  >>>>F***** 
+0

これは、実行時のパフォーマンスは何か不思議です。私は、個々の「WHEN」のケースが(パラレルではなく)順番に評価されれば、不必要な評価を避けるためにツリーに並べ替えることができることに注意します。 – Dai

+0

この操作全体はどのくらいの頻度で実行されますか?パフォーマンスは本当にここで心配する必要がありますか? – shawnt00

+0

このソリューションでは、正の数の前に負の数を配置しません。これは、最後の行を、 'charindex( ' - '、apt)= 0とした後に '+' else ' - ' end/* collat​​e Latin1_General_BIN * /' –

関連する問題