Com base em seus dados de teste, mas isso funciona com dados arbitrários. Isso funciona com qualquer número de elementos na string.
Registre um tipo composto composto por um
text
e um integer
valor uma vez por banco de dados. Eu chamo de ai
:CREATE TYPE ai AS (a text, i int);
O truque é formar um array de
ai
de cada valor na coluna. regexp_matches()
com o padrão (\D*)(\d*)
e o g
A opção retorna uma linha para cada combinação de letras e números. Mais uma linha pendente irrelevante com duas strings vazias '{"",""}'
Filtrar ou suprimir apenas aumentaria o custo. Agregue isso em um array, depois de substituir strings vazias (''
) com 0
no integer
componente (como ''
não pode ser convertido em integer
). NULL
os valores são classificados primeiro - ou você precisa criá-los em maiúsculas - ou usar todo o shebang em um STRICT
funcionar como @Craig propõe. Postgres 9.4 ou posterior
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<>mexa aqui
Postgres 9.1 (resposta original)
Testado com PostgreSQL 9.1.5, onde
regexp_replace()
teve um comportamento um pouco diferente. 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
Adicione
regexp_replace (left(data, 1), '[1-9]', '0')
como primeiro ORDER BY
item para cuidar de dígitos iniciais e strings vazias. {}()"',
pode ocorrer, você teria que escapar deles de acordo.Sugestão do @Craig para usar um
ROW
expressão cuida disso.
O método org.postgresql.jdbc3.Jdbc3Array.getArrayImpl(long,int,Map) ainda não foi implementado.
Isso já foi corrigido:http://sqlfiddle.com/#!17/fad6e/1