Bygger på dina testdata, men det här fungerar med godtyckliga data. Detta fungerar med valfritt antal element i strängen.
Registrera en sammansatt typ som består av en text
och ett integer
värde en gång per databas. Jag kallar det ai
:
CREATE TYPE ai AS (a text, i int);
Tricket är att bilda en array av ai
från varje värde i kolumnen.
regexp_matches()
med mönstret (\D*)(\d*)
och g
alternativet returnerar en rad för varje kombination av bokstäver och siffror. Plus en irrelevant dinglande rad med två tomma strängar '{"",""}'
Att filtrera eller undertrycka det skulle bara öka kostnaden. Aggregera detta till en array efter att ha ersatt tomma strängar (''
) med 0
i integer
komponent (som ''
kan inte casta till integer
).
NULL
värden sorteras först - eller så måste du använda specialfall för dem - eller använd hela shebang i en STRICT
fungerar som @Craig föreslår.
Postgres 9.4 eller senare
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<>spela här
Postgres 9.1 (ursprungligt svar)
Testad med PostgreSQL 9.1.5, där regexp_replace()
hade ett lite annorlunda beteende.
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
Lägg till regexp_replace (left(data, 1), '[1-9]', '0')
som första ORDER BY
objekt för att ta hand om inledande siffror och tomma strängar.
Om specialtecken som {}()"',
kan inträffa, måste du undkomma dem i enlighet med detta.
@Craigs förslag att använda en ROW
expression tar hand om det.
BTW, detta kommer inte att köras i sqlfiddle, men det gör det i mitt db-kluster. JDBC klarar inte av det. sqlfiddle klagar:
Metoden org.postgresql.jdbc3.Jdbc3Array.getArrayImpl(long,int,Map) är ännu inte implementerad.
Detta har sedan åtgärdats:http://sqlfiddle.com/#!17/fad6e/1