テストデータに基づいて構築しますが、これは任意のデータで機能します。これは、文字列内の任意の数の要素で機能します。
1つのtext
で構成される複合型を登録します および1つのinteger
データベースごとに1回の値。私はそれをai
と呼んでいます :
CREATE TYPE ai AS (a text, i int);
秘訣は、ai
の配列を形成することです 列の各値から。
regexp_matches()
パターン(\D*)(\d*)
およびg
オプションは、文字と数字の組み合わせごとに1行を返します。さらに、2つの空の文字列を含む1つの無関係なぶら下がり行'{"",""}'
フィルタリングまたは抑制すると、コストが増えるだけです。空の文字列(''
を置き換えた後、これを配列に集約します )with 0
integer
コンポーネント(''
として integer
にキャストできません 。
NULL
値は最初に並べ替えられます(または、特殊なケースで指定する必要があります)。または、STRICT
でシバン全体を使用します @Craigが提案するような機能。
Postgres9.4以降
SELECT data
FROM alnum
ORDER BY ARRAY(SELECT ROW(x[1], CASE x[2] WHEN '' THEN '0' ELSE x[2] END)::ai
FROM regexp_matches(data, '(\D*)(\d*)', 'g') x)
, data;
db<>ここでフィドル
Postgres 9.1(元の回答)
PostgreSQL 9.1.5でテスト済み。ここで、regexp_replace()
動作が少し異なりました。
SELECT data
FROM (
SELECT ctid, data, regexp_matches(data, '(\D*)(\d*)', 'g') AS x
FROM alnum
) x
GROUP BY ctid, data -- ctid as stand-in for a missing pk
ORDER BY regexp_replace (left(data, 1), '[0-9]', '0')
, array_agg(ROW(x[1], CASE x[2] WHEN '' THEN '0' ELSE x[2] END)::ai)
, data -- for special case of trailing 0
regexp_replace (left(data, 1), '[1-9]', '0')
を追加します 最初のORDER BY
先頭の数字と空の文字列を処理するアイテム。
{}()"',
などの特殊文字の場合 発生する可能性がある場合は、それに応じてそれらをエスケープする必要があります。
@CraigによるROW
の使用の提案 表現がそれを処理します。
BTW、これはsqlfiddleでは実行されませんが、私のdbクラスターでは実行されます。 JDBCはそれに対応していません。 sqlfiddleの文句:
メソッドorg.postgresql.jdbc3.Jdbc3Array.getArrayImpl(long、int、Map)はまだ実装されていません。
これはその後修正されました:http://sqlfiddle.com/#!17 / fad6e / 1