データベースには、次の形式のさまざまな英数字の文字列があります。
10_asdaasda
100_inkskabsjd
11_kancaascjas
45_aksndsialcn
22_dsdaskjca
100_skdnascbka
基本的に、文字列の前にある数字、次に文字列名自体で並べ替えられるようにしたいのですが、もちろん文字は1つずつ比較されるので、Order by nameの結果は次のようになります。
10_asdaasda
100_inkskabsjd
100_skdnascbka
11_kancaascjas
22_dsdaskjca
45_aksndsialcn
私が好む順序の代わりに:
10_asdaasda
11_kancaascjas
22_dsdaskjca
45_aksndsialcn
100_inkskabsjd
100_skdnascbka
正直なところ、文字列が前の数字で並べ替えられていれば問題ありません。私はPostgreSQLに詳しくないので、これを行うための最良の方法が何であるかはわかりませんでした。私はどんな助けにも感謝します!
理想的な方法は、データを正規化し、列の2つのコンポーネントを2つの個別の列に分割することです。タイプinteger
の1つ、text
の1つ。
現在のテーブルを使用すると、ここに示すようなことができます。
_WITH x(t) AS (
VALUES
('10_asdaasda')
,('100_inkskabsjd')
,('11_kancaascjas')
,('45_aksndsialcn')
,('22_dsdaskjca')
,('100_skdnascbka')
)
SELECT t
FROM x
ORDER BY (substring(t, '^[0-9]+'))::int -- cast to integer
,substring(t, '[^0-9_].*$') -- works as text
_
同じ substring()
式 を使用して列を分割できます。
正規表現は多少フォールトトレラントです。
最初の正規表現は、左から最も長い数値文字列を選択します。数字が見つからない場合はNULL
になるため、integer
へのキャストは失敗しません。
2番目の正規表現は、数字または「_」ではない最初の文字から残りの文字列を選択します。
とにかく、下線がセパレータとして明確である場合、 split_part()
の方が高速です。
_ORDER BY (split_part(t, '_', 1)::int
,split_part(t, '_', 2)
_
_SELECT name
FROM nametable
ORDER BY (split_part(name, '_', 1)::int
,split_part(name, '_', 2)
_
部分文字列で正規表現を使用できます
order by substring(column, '^[0-9]+')::int, substring(column, '[^0-9]*$')
式のインデックスでそれを行う方法があります。それは私の好ましい解決策ではありません(私はブラッドのために行くでしょう)が、あなたは次の式にインデックスを作成することができます(それを行う他の方法があります):
_CREATE INDEX idx_name ON table (CAST(SPLIT_PART(columname, '_', 1) AS integer));
_
次に、下線文字の前の数字が必要になるたびに、次のようにCAST(SPLIT_PART(columname, '_', 1) AS integer)
で検索して並べ替えることができます。
_SELECT * FROM table ORDER BY CAST(SPLIT_PART(columname, '_', 1) AS integer);
_
SPLIT_PART(columname, '_', 2)
にインデックスを作成し、それに応じて並べ替えることで、文字列部分に同じことを行うことができます。
しかし、私が言ったように、私はこの解決策を非常に醜いと感じています。私は間違いなく他の2つの列(1つは数値用、もう1つは文字列用)を使用し、ここで言及した列を削除することもできます。
数値データ型のデータベースに新しい列を追加し、新しいレコードを永続化するときに、既存の文字列値のプレフィックスと同じ値に設定する必要があります。
次に、適切に入力された数値列にインデックスを作成して、並べ替えることができます。