2010-11-03 12 views
31

Encontré esto hace algún tiempo y lo he estado usando desde entonces; sin embargo, mirándolo hoy, me di cuenta de que no entiendo completamente por qué funciona. ¿Alguien puede arrojar algo de luz sobre mí?ORDEN personalizado BY Explicación

ORDER BY s.type!= 'Nails', 
      s.type!= 'Bolts', 
      s.type!= 'Washers', 
      s.type!= 'Screws', 
      s.type!= 'Staples', 
      s.type!= 'Nuts', ... 

Si ordeno por tipo, ordena en orden alfabético. Si uso el ejemplo de arriba, usa el mismo orden que las posiciones de línea. Lo que no entiendo es el uso de! =. Si uso =, aparece en el orden opuesto. No puedo entender el concepto de esto.

Me razonaría que usar = en lugar de! = 'S arriba colocaría Nails primero en posición, pero no lo hace, lo coloca en el último. Supongo que mi pregunta es esta: ¿Por qué tengo que usar! =, No = en esta situación?

+14

lo tanto, si no entiendo algo, a pesar de que me gusta la elegancia y la simplicidad de una solución, que debería mantener las manos sobre los oídos y repetir "La, la, la ". No me gusta este enfoque; Prefiero aprender algo nuevo y sentirme cómodo con él. –

Respuesta

23

Nunca lo he visto, pero parece tener sentido.

Al principio ordena por s.type != 'Nails'. Esto es false para cada fila que contiene Nails en la columna type. Después de eso, está ordenado por Bolts. Nuevamente para todas las columnas que sí contienen Bolts como type, esto se evalúa como falso. Y así.

Una pequeña prueba revela que false está ordenada antes de true. Por lo tanto, tiene lo siguiente: Primero obtiene todas las filas con Nails en la parte superior porque el ORDER BY de acuerdo con false y false es lo primero. Las filas restantes se ordenan por el segundo criterio ORDER BY. Y así.

 
type  | != Nails | != Bolts | != Washers 
'Nails' | false | true  | true 
'Bolts' | true  | false | true 
'Washers' | true  | true  | false 
+1

No te olvides de los NULL. –

+1

Esto es puramente un pensamiento. Pero supongo que ordena falso antes de true, debido a sus respetados valores enteros de 0 y 1 donde 0 (falso) viene antes de 1 (verdadero). –

41

Cada expresión se evalúa como bool y se trata como 0 para falso y 1 para verdadero y ordenado adecuadamente. Aunque esto funciona, la lógica es difícil de seguir (y mantener). Lo que uso es una función que encuentra el índice de un valor en una matriz.

ORDER BY idx(array['Nails','Bolts','Washers','Screws','Staples','Nuts'], s.type) 

Esto es mucho más fácil de seguir. Las uñas se ordenan primero y las nueces se ordenan al final. Puede ver cómo crear la función idx en el repositorio de fragmentos de Postgres. http://wiki.postgresql.org/wiki/Array_Index

+2

debe ser 'array_position' –

+1

@EbenGeer solo en 9.5 y más – DarkMukke

15

@Scott Bailey gran idea sugerida. Pero puede ser aún más simple (no es necesario crear una función personalizada) desde PostgreSQL 9.5. Sólo tiene que utilizar la función array_position:

ORDER BY array_position(array['Nails','Bolts','Washers','Screws','Staples','Nuts'], s.type) 
+0

Esta respuesta me ahorró mucho trabajo. ¡Gracias! –

+0

lo probé en mi instancia dev, fue genial, la producción sigue en 9.3 ...no tan bueno – DarkMukke

+2

Esto se aplica a las columnas del tipo 'Text', intenté esto con un tipo de columna' character' y la función arrojó un error - con suerte esto ayuda :) –

1

con array_position, tiene que tener el mismo tipo que está consultando en contra.

por ejemplo:

select array_position(array['foo'::char,'bar','baz'::char], 'bar'); 
select array_position(array['foo'::char,'bar','baz'::char], 'baz'::char);