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:https://sqlfiddle.com/#!17/fad6e/1