MySQL - ORDER BY valores dentro de IN ()

107

Espero ordenar los elementos devueltos en la siguiente consulta por el orden en que se ingresaron en la función IN () .

ENTRADA:

SELECT id, name FROM mytable WHERE name IN ('B', 'A', 'D', 'E', 'C');

SALIDA:

|   id   |   name  |
^--------^---------^
|   5    |   B     |
|   6    |   B     |
|   1    |   D     |
|   15   |   E     |
|   17   |   E     |
|   9    |   C     |
|   18   |   C     |

¿Algunas ideas?

Mate
fuente

Respuestas:

231
SELECT id, name
FROM mytable
WHERE name IN ('B', 'A', 'D', 'E', 'C')
ORDER BY FIELD(name, 'B', 'A', 'D', 'E', 'C')

La función FIELD devuelve la posición de la primera cadena en la lista restante de cadenas.

Sin embargo, es mucho mejor en términos de rendimiento tener una columna indexada que represente su orden de clasificación y luego ordenar por esta columna.

Ayman Hourieh
fuente
9
@Vladimir: sí, es específico de MySQL. La pregunta tiene la etiqueta mysql.
Ayman Hourieh
Excelente, reemplazo de la función de "decodificación" de Oracle después del cambio de base de datos.
Martin Lyne
7
Cuidado. Cualquier valor de propiedad desconocido (que no esté en la lista) tendrá prioridad sobre los valores conocidos, es decir FIELD(letter, 'A', 'C'), la lista primero devolverá las entradas con la letra B primero (asumiendo un conjunto de registros con A | B | Cvalores). Para evitar eso, invierta la lista y use DESC, es decir FIELD(letter, 'C', 'A') DESC.
Gajus
¿Cómo logro esto en el servidor SQL?
user123456
29

Otra opción desde aquí: http://dev.mysql.com/doc/refman/5.0/en/sorting-rows.html

select * 
from tablename 
order by priority='High' DESC, priority='Medium' DESC, priority='Low" DESC;

Entonces, en su caso (no probado) sería

SELECT id, name
FROM mytable
WHERE name IN ('B', 'A', 'D', 'E', 'C')
ORDER BY name = 'B', name = 'A', name = 'D', name =  'E', name = 'C';

Dependiendo de lo que estés haciendo, lo encontré un poco peculiar, pero siempre lo hice funcionar después de jugar un poco con él.

Joedevon
fuente
Esto puede ser mejor que usar la función field () como otra respuesta sugerida porque usar field () excluirá el uso del índice, pero tiene la posibilidad de usar un índice usando este método (aunque no estoy seguro de qué tan bien podría usar el índice)
ʞɔıu
4

Prueba algo como

... ORDER BY (CASE NAME WHEN 'B' THEN 0 WHEN 'A' THEN 1 WHEN ...
Vladimir Dyuzhev
fuente
3

Puede ser que esto pueda ayudar a alguien (p_CustomerId se pasa en SP):

SELECT CompanyAccountId, CompanyName
FROM account
LEFT JOIN customer where CompanyAccountId = customer.AccountId
GROUP BY CompanyAccountId
ORDER BY CASE WHEN CompanyAccountId IN (SELECT AccountId 
                                          FROM customer
                                          WHERE customerid= p_CustomerId) 
                 THEN 0
                 ELSE 1
          END, CompanyName;

Descripción: Quiero mostrar la lista de cuentas. Aquí estoy pasando una identificación de cliente en sp. Ahora enumerará los nombres de cuentas con cuentas vinculadas a las que se muestran los clientes en la parte superior, seguidas de otras cuentas en orden alfabético.

huno
fuente
2

Necesita otra columna (numérica) en su tabla, en la que especifica el orden de clasificación. La cláusula IN no funciona de esta manera.

B - 1
A - 2
D - 3
E - 4
C - 5
Robert Harvey
fuente
2
El orden deseado puede ser por consulta.
Vladimir Dyuzhev
0

Solo usa

order by INSTR( ',B,C,D,A,' ,  concat(',' , `field`, ',' ) )

evitar la situación como

 INSTR('1,2,3,11' ,`field`) 

terminará con una fila de resultados desordenada: 1 y 11 alternativos

PercyQQ
fuente