ユーザーが期待するように、アルファベットと数字の混合リストを並べ替えて表示するにはどうすればよいでしょうか?
-
23-08-2019 - |
質問
私たちのアプリケーションには、 CustomerNumber
分野。私たちは何百人もの異なる人々がシステムを使用しています (それぞれが独自のログイン情報と独自のリストを持っています) CustomerNumber
s)。個々のユーザーの顧客数は最大でも 100,000 人です。多くは100未満です。
顧客番号フィールドに実際の数字のみを入力する人もいれば、複数の値を組み合わせて使用する人もいます。システムでは、A ~ Z、0 ~ 9、またはダッシュの 20 文字が許可され、これらは VARCHAR2(20) に格納されます。小文字はすべて大文字にしてから保存されます。
ここで、特定のユーザーのすべての顧客を顧客番号順にリストする単純なレポートがあるとします。例えば
SELECT CustomerNumber,CustomerName
FROM Customer
WHERE User = ?
ORDER BY CustomerNumber;
数字のみを使用する人は、単純なアルファベットによる並べ替え (「10」が「9」の前に来る) を見たくないので、これは単純な解決策です。
ユーザーにデータに関して不必要な質問をしたくありません。
私は Oracle を使用していますが、他のデータベース用のソリューションをいくつか見るのは興味深いと思います。回答がどのデータベースで機能するかを含めてください。
これを実装する最善の方法は何だと思いますか?
解決
Oracle 10g の場合:
SELECT cust_name
FROM t_customer c
ORDER BY
REGEXP_REPLACE(cust_name, '[0-9]', ''), TO_NUMBER(REGEXP_SUBSTR(cust_name, '[0-9]+'))
これは、番号の位置ではなく、最初に出現した番号でソートします。e.:
customer1 < customer2 < customer10
cust1omer ? customer1
cust8omer1 ? cust8omer2
, 、ここで、 ?
順序が定義されていないことを意味します。
ほとんどの場合、これで十分です。
ケースにソート順序を強制するには 2
, を追加できます。 REGEXP_INSTR(cust_name, '[0-9]', n)
に ORDER BY
リスト n
回、最初の出現時に順序を強制する n
- 番目 (2nd
, 3rd
など) 数字のグループ。
ケースにソート順序を強制するには 3
, を追加できます。 TO_NUMBER(REGEXP_SUBSTR(cust_name, '[0-9]+', n))
に ORDER BY
リスト n
回、順序を強制する n
- 番目。数字のグループ。
実際には、私が作成したクエリで十分です。
これらの式に関数ベースのインデックスを作成できますが、ヒントとワンパスを使用して強制的にインデックスを作成する必要があります。 SORT ORDER BY
とにかく実行されます。 CBO
関数ベースのインデックスを十分に信頼していないため、 ORDER BY
それらの上に。
他のヒント
おそらくあなたの最善の策は、別の列を事前に計算して注文することを利用して表示するために顧客番号を使用することです。これはおそらく、固定長に0パディング任意の内部整数を伴うだろう。
他の可能性は、あなたが返された結果の事後選択ソートを行うことです。
ジェフアトウッドは、一緒にブログの投稿を入れています方法については、一部の人々は、人間に優しいソート順を計算します。
は、CustomerNumberのは、純粋に数値である場合にのみ使用されている数値列[CustomerNumberInt]有し得る(そうでなければNULLを[1])、その後
ORDER BY CustomerNumberInt, CustomerNumber
[1]あなたのSQLのバージョンが、ORDER BYでNULLをどのように扱うかに応じて、ゼロにそれをデフォルトにしたいかもしれません(または無限大!)
私は似た恐ろしい状況を持っており、それ(SQLServerの)
に対処するための適切恐ろしい機能を開発しました私の状況では、私は(これは学生のための作業追跡システムであるので、この文脈での単位は、彼らがやっているコースを表して)「単位」のテーブルを持っています。ユニットは、大部分は純粋に数値のコードを、持っているが、様々な理由のためにそれはvarchar型に作られた、彼らは最大5文字でいくつかの接頭辞ことにしました。そこで、彼らは通常、ソートする53123237356を期待するだけでなく、T53、T123、T237、T356
UnitCodeはNVARCHAR(30)である
ここでは関数の本体です:
declare @sortkey nvarchar(30)
select @sortkey =
case
when @unitcode like '[^0-9][0-9]%' then left(@unitcode,1) + left('000000000000000000000000000000',30-(len(@unitcode))) + right(@unitcode,len(@unitcode)-1)
when @unitcode like '[^0-9][^0-9][0-9]%' then left(@unitcode,2) + left('000000000000000000000000000000',30-(len(@unitcode))) + right(@unitcode,len(@unitcode)-2)
when @unitcode like '[^0-9][^0-9][^0-9][0-9]%' then left(@unitcode,3) + left('000000000000000000000000000000',30-(len(@unitcode))) + right(@unitcode,len(@unitcode)-3)
when @unitcode like '[^0-9][^0-9][^0-9][^0-9][0-9]%' then left(@unitcode,4) + left('000000000000000000000000000000',30-(len(@unitcode))) + right(@unitcode,len(@unitcode)-4)
when @unitcode like '[^0-9][^0-9][^0-9][^0-9][^0-9][0-9]%' then left(@unitcode,5) + left('000000000000000000000000000000',30-(len(@unitcode))) + right(@unitcode,len(@unitcode)-5)
when @unitcode like '%[^0-9]%' then @unitcode
else left('000000000000000000000000000000',30-len(@unitcode)) + @unitcode
end
return @sortkey
しかし私はそれが動作する、ことを書いた後、顔に自分自身を撮影したかったし、それが実行されるときに、サーバーを殺すことではないようです。
私は、SQL Serverと作業偉大でこれを使用:すべてが同じ文字列の長さであるように、ここでは解決策は、パッドに前の文字と数値である。
。ここではその手法を用いた例である:
select MyCol
from MyTable
order by
case IsNumeric(MyCol)
when 1 then Replicate('0', 100 - Len(MyCol)) + MyCol
else MyCol
end
100は、その列の実際の長さに置き換える必要があります。