2011-08-10 11 views
8

ejecución de esta consulta:Postgresql ordenar datos alfanuméricos mixtos

select name from folders order by name 

devuelve estos resultados:

alphanumeric 
a test 
test 20 
test 19 
test 1 
test 10 

pero esperaba:

a test 
alphanumeric 
test 1 
test 10 
test 19 
test 20 

¿Qué pasa aquí?

+1

Parece raro: ''test 20 '<' test 19''. ¿Qué 'LC_COLLATE' tiene al examinar' SHOW lc_collate; '? Tengo 'en_US.UTF-8' y devuelve la salida exactamente deseada con' ORDER BY name ASC'. –

+0

Obtengo lo mismo, también. Acabo de hacer 'seleccionar 'alfanumérico' <'a test'' y obtuve' f'. –

+1

para el registro, publiqué una respuesta que lo señala a la entrada manual para la intercalación. fue votado como no ser abrazado, lo suficientemente amoroso, así que lo borré. pero creo que deberías comenzar allí. –

Respuesta

3

Usted puede ser capaz de forma manual ordenar por dividir el texto en caso de que haya detrás de los números, así:

SELECT * FROM sort_test 
ORDER BY SUBSTRING(text FROM '^(.*?)(\\d+)?$'), 
     COALESCE(SUBSTRING(text FROM ' (\\d+)$')::INTEGER, 0); 

Esto ordenará el texto de la columna, por primera vez por todos los caracteres sin incluir opcionalmente un espacio que termina seguido por dígitos, luego por esos dígitos opcionales.

Funcionó bien en mi examen.

La actualización solucionó la clasificación de solo cadena con un simple coalesce (duh).

+0

¿Por qué el voto a favor? Funciona y resuelve la situación. No es la * mejor * solución, pero no implica cambiar la estructura de la base de datos. Al menos comenta si sientes la necesidad de rechazar votos. – OverZealous

+0

-1 para kluge extraño que no resuelve el problema real. (¿Qué pasa con las cadenas con espacios y/o números múltiples?) Consulte los comentarios anteriores sobre intercalaciones. –

+0

No diría que es un * extraño kludge *. Agrega la capacidad de ordenar números finales numéricamente, sin requerir una versión específica de PG. Maneja muy bien los números * finales, por lo que funciona bien para las carpetas numeradas secuencialmente. Maneja múltiples espacios, porque solo está verificando para asegurarse de que haya al menos un espacio antes de los dígitos finales. Si lo intentaras, verías que funcionó, en lugar de asumirlo. – OverZealous

16

simplemente puede emitir name la columna de tipo de datos que permite bytea cotejar independiente del pedido:

SELECT name 
FROM folders 
ORDER BY name::bytea; 

Resultado:

 name  
-------------- 
a test 
alphanumeric 
test 1 
test 10 
test 19 
test 20 
(6 rows) 
+1

¡Maestro! ¡Esta respuesta es definitivamente lo que he estado buscando durante las últimas 2 horas! Procedente de Mysql que no da error al convertir varchar en entero cuando no hay número ... – gabn88

+0

Esto corrige la clasificación con espacios iniciales que 'TRIM' no resolvería. –

2

respuesta exceso de celo me ayudó, pero no funciona si la cadena en el la base de datos comenzó con números seguidos por caracteres adicionales.

A continuación trabajó para mí:

SELECT name 
FROM folders 
ORDER BY 
COALESCE(SUBSTRING(name FROM '^(\\d+)')::INTEGER, 99999999), 
SUBSTRING(name FROM '^\\d* *(.*?)(\\d+)?$'), 
COALESCE(SUBSTRING(name FROM ' (\\d+)$')::INTEGER, 0), 
name; 

Así que éste:

  1. Extractos el primer número de la cadena, o utiliza 99999999.
  2. Extractos la cadena que sigue a la posible primera número.
  3. extrae un número de seguimiento, o utiliza la última SQL 0.
0

de Tor trabajó para mí. Sin embargo, si llama a este código desde php, necesita agregar barras adicionales.

SELECT name 
FROM folders 
ORDER BY 
COALESCE(SUBSTRING(name FROM '^(\\\\d+)')::INTEGER, 99999999), 
SUBSTRING(name FROM '^\\\\d* *(.*?)(\\\\d+)?$'), 
COALESCE(SUBSTRING(name FROM ' (\\\\d+)$')::INTEGER, 0), 
name; 
2

Todos estos métodos ordenados mi selección en orden alfabético:

test 1 
test 10 
test 2 
test 20 

Esta solución funcionó para mí (LC_COLLATE: 'ru_RU.UTF8'):

SELECT name 
FROM folders 
ORDER BY SUBSTRING(name FROM '([0-9]+)')::BIGINT ASC, name; 

test 1 
test 2 
test 10 
test 20 
0

respuesta de una VLK arriba me ayudó mucho, pero clasificó los artículos solo por la parte numérica, que en mi caso quedó en segundo lugar. Mis datos eran como (escritorio 1, escritorio 2, escritorio 3 ...) una parte de cuerda, un espacio y una parte numérica. La sintaxis en la respuesta de A Vlk devolvió los datos ordenados por el número, y en eso fue la única respuesta de lo anterior lo que hizo el truco. Sin embargo, cuando la parte de la cuerda era diferente, (por ejemplo, escritorio 3, escritorio 4, mesa 1, escritorio 5 ...) la tabla 1 obtendría primero del escritorio 2. Lo arreglé usando la siguiente sintaxis:

...order by SUBSTRING(name,'\\w+'), SUBSTRINGname FROM '([0-9]+)')::BIGINT ASC;