Opierając się na danych testowych, ale działa to z dowolnymi danymi. Działa to z dowolną liczbą elementów w ciągu.
Zarejestruj typ złożony składający się z jednego text
i jedna integer
wartość raz na bazę danych. Nazywam to ai
:
CREATE TYPE ai AS (a text, i int);
Sztuczka polega na utworzeniu tablicy ai
z każdej wartości w kolumnie.
regexp_matches()
ze wzorem (\D*)(\d*)
i g
opcja zwraca jeden wiersz dla każdej kombinacji liter i cyfr. Plus jeden nieistotny wiszący wiersz z dwoma pustymi ciągami '{"",""}'
Filtrowanie lub tłumienie tylko zwiększałoby koszty. Zagreguj to do tablicy, po zastąpieniu pustych ciągów (''
) z 0
w integer
komponent (jako ''
nie można rzutować na integer
).
NULL
wartości najpierw posortuj - lub musisz umieścić je w specjalnej wielkości - lub użyj całego zbioru w STRICT
funkcjonować tak, jak proponuje @Craig.
Postgres 9.4 lub nowszy
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<>graj tutaj
Postgres 9.1 (oryginalna odpowiedź)
Testowane z PostgreSQL 9.1.5, gdzie regexp_replace()
miał nieco inne zachowanie.
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
Dodaj regexp_replace (left(data, 1), '[1-9]', '0')
jako pierwszy ORDER BY
element do obsługi wiodących cyfr i pustych ciągów.
Jeśli znaki specjalne, takie jak {}()"',
może wystąpić, musisz odpowiednio uciec przed nimi.
Sugestia @Craiga, aby użyć ROW
express o to zadba.
BTW, to nie zostanie wykonane w sqlfiddle, ale działa w moim klastrze db. JDBC nie jest do tego zdolne. sqlfiddle narzeka:
Metoda org.postgresql.jdbc3.Jdbc3Array.getArrayImpl(long,int,Map) nie została jeszcze zaimplementowana.
Zostało to naprawione:http://sqlfiddle.com/#!17/fad6e/1