2009-10-27 13 views
35

tengo la siguiente tablaMantener el orden en MySQL "IN" consulta

DROP TABLE IF EXISTS `test`.`foo`; 
CREATE TABLE `test`.`foo` (
    `id` int(10) unsigned NOT NULL auto_increment, 
    `name` varchar(45) NOT NULL, 
    PRIMARY KEY (`id`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1; 

entonces trato de obtener los registros en base a la clave primaria

SELECT * FROM foo f where f.id IN (2, 3, 1); 

luego me sale el siguiente resultado

+----+--------+ 
| id | name | 
+----+--------+ 
| 1 | first | 
| 2 | second | 
| 3 | third | 
+----+--------+ 
3 rows in set (0.00 sec) 

Como se puede ver, el resultado se ordena por id. Lo que intento lograr es obtener los resultados ordenados en la secuencia que estoy proporcionando en la consulta. Teniendo en cuenta este ejemplo debería devolver

+----+--------+ 
| id | name | 
+----+--------+ 
| 2 | second | 
| 3 | third | 
| 1 | first | 
+----+--------+ 
3 rows in set (0.00 sec) 
+0

Compruebe esta respuesta en el sitio de MySQL: http://forums.mysql.com/read.php?97,210905,210918#msg-210918 - Creo que tendrá problemas para esperar en() comportarse así MySQL realmente no ordena los resultados a menos que explícitamente lo indique, y no tiene nada en los datos que lo ordenarán de la manera que desee. – artlung

Respuesta

69

Como la otra respuesta menciona: la consulta que publicó no tiene nada en qué orden desea obtener los resultados, solo los resultados que desea obtener.

de pedir sus resultados, me gustaría utilizar ORDER BY FIELD():

lista
SELECT * FROM foo f where f.id IN (2, 3, 1) 
ORDER BY FIELD(f.id, 2, 3, 1); 

El argumento de campo puede ser de longitud variable.

+1

Oh, sí, eso también funciona. +1 –

+0

Me interesaría ver si alguno de los métodos tiene una ventaja de rendimiento en el caso general de pedir filas por ID. Siempre he usado FIELD() pero he visto algunos ejemplos de código que usan el método FIND_IN_SET() que publicaste. –

21

Los valores en un predicado IN() se considera como un conjunto, y el resultado devuelto por una consulta SQL no tiene manera de inferir automáticamente el fin de la establecida.

En general, el orden de cualquier consulta SQL es arbitrario a menos que especifique una orden con una cláusula ORDER BY.

Puede utilizar una función de MySQL FIND_IN_SET() a hacer lo que quiera:

SELECT * FROM foo f where f.id IN (2, 3, 1) 
ORDER BY FIND_IN_SET(f.id, '2,3,1'); 

Tenga en cuenta que la lista de argumentos a FIND_IN_SET() no es una lista de longitud variable como los argumentos de IN(). Tiene que ser una cadena literal o SET.


preguntas sobre el desempeño Re: Tengo curiosidad también, así que trataron ambos FIND_IN_SET() y FIELD() métodos contra mi copia de los datos Stackoverflow:

con ningún índice en VoteTypeId:

SELECT * FROM Votes ORDER BY FIND_IN_SET(VoteTypeId, '13,1,12,2,11,3,10,4,9,5,8,6,7'); 

3618992 rows in set (31.26 sec) 
3618992 rows in set (29.67 sec) 
3618992 rows in set (28.52 sec) 

SELECT * FROM Votes ORDER BY FIELD(VoteTypeId, 13,1,12,2,11,3,10,4,9,5,8,6,7); 

3618992 rows in set (37.30 sec) 
3618992 rows in set (49.65 sec) 
3618992 rows in set (41.69 sec) 

Con un índice en VoteTypeId:

SELECT * FROM Votes ORDER BY FIND_IN_SET(VoteTypeId, '13,1,12,2,11,3,10,4,9,5,8,6,7'); 

3618992 rows in set (14.71 sec) 
3618992 rows in set (14.81 sec) 
3618992 rows in set (25.80 sec) 

SELECT * FROM Votes ORDER BY FIELD(VoteTypeId, 13,1,12,2,11,3,10,4,9,5,8,6,7); 

3618992 rows in set (19.03 sec) 
3618992 rows in set (14.59 sec) 
3618992 rows in set (14.43 sec) 

Conclusión: con pruebas limitadas, no hay una gran ventaja para ninguno de los métodos.

+1

mucho mejor que CASE 'x' ENTONCES 1, CASO 'y' ENTONCES 2 para una columna de orden arbitraria – dnagirl

+0

gracias por aclarar eso - fui por la otra respuesta ya que FIELD con argumentos variables parece más intuitivo para mí. pero también me interesaría una comparación de rendimiento. – msparer

+0

Sí, no creo que haya mucha o ninguna diferencia, pero gracias por los resultados de la prueba :) –