sql ORDER BY múltiples valores en un orden específico?

94

Ok, tengo una tabla con una clave indexada y un campo no indexado. Necesito encontrar todos los registros con un cierto valor y devolver la fila. Me gustaría saber si puedo ordenar por múltiples valores.

Ejemplo:

id     x_field
--     -----
123    a
124    a
125    a
126    b
127    f
128    b
129    a
130    x
131    x
132    b
133    p
134    p
135    i

pseudo: quisiera que los resultados se ordenen así, where ORDER BY x_field = 'f', 'p', 'i', 'a'

SELECT *
FROM table
WHERE id NOT IN (126)
ORDER BY x_field 'f', 'p', 'i', 'a'

Entonces los resultados serían:

id     x_field
--     -----
127    f
133    p
134    p
135    i
123    a
124    a
125    a
129    a

La sintaxis es válida pero cuando ejecuto la consulta nunca devuelve ningún resultado, incluso si la limito a 1 registro. ¿Hay otra forma de hacer esto?

Piense en el x_field como resultados de la prueba y necesito validar todos los registros que caen en la condición. Quería ordenar los resultados de la prueba por valores fallidos, valores pasados. Entonces podría validar los valores fallidos primero y luego los valores pasados ​​usando ORDER BY.

Lo que no puedo hacer:

  • GROUP BY, ya que necesito devolver los valores de registro específicos
  • DONDE x_field IN ('f', 'p', 'i', 'a'), necesito todos los valores ya que estoy tratando de usar una consulta para varias pruebas de validación. Y los valores de x_field no están en orden DESC / ASC

Después de escribir esta pregunta, estoy empezando a pensar que necesito repensar esto, ¡LOL!

Phill Pafford
fuente
¿Quizás un sindicato en su lugar? Construya consultas separadas en el orden en el que desea que se devuelvan los resultados, luego haga una unión de esas consultas.
kinakuta

Respuestas:

181
...
WHERE
   x_field IN ('f', 'p', 'i', 'a') ...
ORDER BY
   CASE x_field
      WHEN 'f' THEN 1
      WHEN 'p' THEN 2
      WHEN 'i' THEN 3
      WHEN 'a' THEN 4
      ELSE 5 --needed only is no IN clause above. eg when = 'b'
   END, id
gbn
fuente
29

Puedes usar LEFT JOIN con "VALUES ('f', 1), ('p', 2), ('a', 3), ('i', 4)" y usar la segunda columna en tu orden -por expresión. Postgres usará un Hash Join, que será mucho más rápido que un CASE enorme si tiene muchos valores. Y es más fácil de autogenerar.

Si esta información de pedido es fija, entonces debería tener su propia tabla.

bobflux
fuente
6
¡Esta es, con mucho, la solución más elegante!
jnns
28

Tratar:

ORDER BY x_field='F', x_field='P', x_field='A', x_field='I'

Estaba en el camino correcto, pero al poner x_field solo en el valor F, los otros 3 se trataron como constantes y no se compararon con nada en el conjunto de datos.

Marc B
fuente
¿Postgres admite booleanos implícitos? Si es así, ¿cómo se ordena booleano?
gbn
Me gustó esta solución pero no devolvió nada de nuevo.
Phill Pafford
@gbn, Sí y falso <verdadero. Hubiera esperado que esto funcionara.
Andrew Lazarus
7
Sí, funciona evento en Postgres. Tenga en cuenta que esta solución es que obtiene los resultados ordenados en orden inverso. Así que tienes que poner los campos en orden inverso: ORDER BY x_field = 'A', x_field = 'I', x_field = 'P', x_field = 'F',
igo
16

Use un caseinterruptor para traducir los códigos en números que se pueden ordenar:

ORDER BY
  case x_field
  when 'f' then 1
  when 'p' then 2
  when 'i' then 3
  when 'a' then 4
  else 5
  end
Guffa
fuente
10

Encontré una solución mucho más limpia para esto:

ORDER BY array_position(ARRAY['f', 'p', 'i', 'a']::varchar[], x_field)

Nota: array_position necesita Postgres v9.5 o superior.

reptil
fuente
1
Es importante tener en cuenta que array_position () solo está disponible en Postgres v9.5 en adelante, afaik.
bigsee
gracias, prefiero esto a los métodos CASE. También funciona con números enteros; array_position(ARRAY[1, 0]::integer[], x_field)
Paul Watson
7

El CASEy ORDER BYsugerencias debería funcionar, pero voy a sugerir un caballo de un color diferente. Suponiendo que solo hay un número razonable de valores para x_fieldy ya sabe cuáles son, cree un tipo enumerado con F, P, A e I como valores (más cualquier otro valor posible que se aplique). Las enumeraciones se ordenarán en el orden implícito en su CREATEdeclaración. Además, puede utilizar nombres de valores significativos (probablemente su aplicación real lo haga y los ha enmascarado por motivos de confidencialidad) sin desperdiciar espacio, ya que solo se almacena la posición ordinal.

Andrés Lázaro
fuente
1

Puede ordenar por una columna seleccionada u otras expresiones.

Aquí un ejemplo, cómo ordenar por el resultado de una declaración de caso:

  SELECT col1
       , col2
    FROM tbl_Bill
   WHERE col1 = 0
ORDER BY -- order by case-statement
    CASE WHEN tbl_Bill.IsGen = 0 THEN 0
         WHEN tbl_Bill.IsGen = 1 THEN 1
         ELSE 2 END

El resultado será una lista que comienza con las filas "IsGen = 0", seguidas de las filas "IsGen = 1" y todas las demás filas al final.

Puede agregar más parámetros de pedido al final:

  SELECT col1
       , col2
    FROM tbl_Bill
   WHERE col1 = 0
ORDER BY -- order by case-statement
    CASE WHEN tbl_Bill.IsGen = 0 THEN 0
         WHEN tbl_Bill.IsGen = 1 THEN 1
         ELSE 2 END,
         col1,
         col2
Código
fuente
Si bien este fragmento de código puede resolver el problema, no explica por qué ni cómo responde a la pregunta. Por favor, incluya una explicación de su código , como que realmente ayuda a mejorar la calidad de su puesto. Recuerde que está respondiendo la pregunta para los lectores en el futuro, y es posible que esas personas no conozcan los motivos de su sugerencia de código.
Samuel Philipp
0

Para alguien que es nuevo en ORDER BY con CASE, esto puede ser útil

ORDER BY 
    CASE WHEN GRADE = 'A' THEN 0
         WHEN GRADE = 'B' THEN 1
         ELSE 2 END
Akitha_MJ
fuente
-2

puede usar la posición (texto en texto) en orden para ordenar la secuencia

Mukesh Kulal
fuente