Sobre la base de sus datos de prueba, pero esto funciona con datos arbitrarios. Esto funciona con cualquier número de elementos en la cadena.
Registre un tipo compuesto formado por un text
y un integer
valor una vez por base de datos. Yo lo llamo ai
:
CREATE TYPE ai AS (a text, i int);
El truco es formar una matriz de ai
de cada valor en la columna.
regexp_matches()
con el patrón (\D*)(\d*)
y el g
La opción devuelve una fila para cada combinación de letras y números. Más una fila colgante irrelevante con dos cadenas vacías '{"",""}'
Filtrarlo o suprimirlo solo agregaría costos. Agregue esto en una matriz, después de reemplazar las cadenas vacías (''
) con 0
en el integer
componente (como ''
no se puede convertir a integer
).
NULL
los valores se ordenan primero, o tiene que ponerlos en un caso especial, o usar todo el shebang en un STRICT
funcionar como propone @Craig.
Postgres 9.4 o 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<>violín aquí
Postgres 9.1 (respuesta original)
Probado con PostgreSQL 9.1.5, donde regexp_replace()
tuvo un comportamiento ligeramente 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
Agregue regexp_replace (left(data, 1), '[1-9]', '0')
como primer ORDER BY
elemento para ocuparse de los dígitos iniciales y las cadenas vacías.
Si caracteres especiales como {}()"',
pueden ocurrir, tendrías que escapar de ellos en consecuencia.
La sugerencia de @Craig de usar una ROW
expresión se encarga de eso.
Por cierto, esto no se ejecutará en sqlfiddle, pero sí en mi clúster de base de datos. JDBC no está a la altura. sqlfiddle se queja:
El método org.postgresql.jdbc3.Jdbc3Array.getArrayImpl(long,int,Map) aún no está implementado.
Esto ya se solucionó:http://sqlfiddle.com/#!17/fad6e/1