Aufbauend auf Ihren Testdaten funktioniert dies aber mit beliebigen Daten. Dies funktioniert mit einer beliebigen Anzahl von Elementen im String.
Registrieren Sie einen zusammengesetzten Typ, der aus einem text
besteht und eine integer
Wert einmal pro Datenbank. Ich nenne es ai
:
CREATE TYPE ai AS (a text, i int);
Der Trick besteht darin, ein Array von ai
zu bilden von jedem Wert in der Spalte.
regexp_matches()
mit dem Muster (\D*)(\d*)
und das g
Die Option gibt eine Zeile für jede Kombination aus Buchstaben und Zahlen zurück. Plus eine irrelevante lose Zeile mit zwei leeren Zeichenfolgen '{"",""}'
Das Filtern oder Unterdrücken würde nur zusätzliche Kosten verursachen. Fassen Sie dies in einem Array zusammen, nachdem Sie leere Zeichenfolgen ersetzt haben (''
) mit 0
in der integer
Komponente (als ''
kann nicht in integer
umgewandelt werden ).
NULL
Werte zuerst sortieren - oder Sie müssen sie in Sonderfällen behandeln - oder den ganzen Kram in einem STRICT
verwenden funktionieren wie @Craig vorschlägt.
Postgres 9.4 oder höher
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<>hier fummeln
Postgres 9.1 (ursprüngliche Antwort)
Getestet mit PostgreSQL 9.1.5, wobei regexp_replace()
hatte ein etwas anderes Verhalten.
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
Fügen Sie regexp_replace (left(data, 1), '[1-9]', '0')
hinzu als erstes ORDER BY
item, um sich um führende Ziffern und leere Zeichenfolgen zu kümmern.
Falls Sonderzeichen wie {}()"',
auftreten können, müssten diese entsprechend maskiert werden.
@Craigs Vorschlag, eine ROW
zu verwenden Ausdruck kümmert sich darum.
Übrigens, dies wird nicht in sqlfiddle ausgeführt, aber in meinem db-Cluster. JDBC ist dem nicht gewachsen. sqlfiddle beschwert sich:
Die Methode org.postgresql.jdbc3.Jdbc3Array.getArrayImpl(long,int,Map) ist noch nicht implementiert.
Dies wurde inzwischen behoben:http://sqlfiddle.com/#!17/fad6e/1