2009-10-27 10 views
35

ho la seguente tabellaordine Mantenere in MySQL "IN" di query

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; 

poi cerco di ottenere i record in base alla chiave primaria

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

Allora ottengo il seguente risultato

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

Come si può vedere, il risultato è ordinato da id. Quello che sto cercando di ottenere è ottenere i risultati ordinati nella sequenza che sto fornendo nella query. Dato questo esempio deve restituire

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

Controlla questa risposta sul sito MySQL: http://forums.mysql.com/read.php?97,210905,210918#msg-210918 - Penso che ti troverai nei guai in attesa di() comportarsi in questo modo MySQL in realtà non ordina i risultati a meno che tu non lo dica esplicitamente, e non hai nulla nei dati che lo ordinerà nel modo desiderato. – artlung

risposta

69

Come l'altra risposta menziona: la query che hai pubblicato non ha nulla su quale ordine desideri i tuoi risultati, solo quali risultati vorresti ottenere.

Per ordinare i risultati, vorrei utilizzare ORDER BY FIELD():

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

L'argomento di campo può essere di lunghezza variabile.

+1

Oh, sì, funziona anche. +1 –

+0

Sarei interessato a vedere se entrambi i metodi hanno un vantaggio in termini di prestazioni nel caso generale di ordinare le righe per ID. Ho sempre usato FIELD() ma ho visto alcuni esempi di codice che utilizzano il metodo FIND_IN_SET() che hai postato. –

21

I valori in un IN() predicato sono considerati come un insieme, e il risultato restituito da una query SQL non ha modo di inferire automaticamente ordine da quella impostata.

In generale, l'ordine di qualsiasi query SQL è arbitrario a meno che non sia un ordine con una clausola ORDER BY.

È possibile utilizzare una funzione di MySQL FIND_IN_SET() di fare ciò che si vuole:

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

Nota che la lista degli argomenti per FIND_IN_SET() non è un elenco di lunghezza variabile, come le argomentazioni di IN(). Deve essere una stringa letterale o SET.


domande Re sulle prestazioni: Sono curioso troppo, così ho provato sia FIND_IN_SET() e FIELD() metodi contro la mia copia dei dati StackOverflow:

senza indice su 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 indice su 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) 

Conclusione: con test limitati, non c'è un grande vantaggio per entrambi i metodi.

+1

molto più bello che CASE 'x' ALLORA 1, CASE 'y' ALLORA 2 per una colonna di ordine arbitrario – dnagirl

+0

grazie per aver chiarito che uno - sono andato per l'altra risposta come CAMPO con argomenti variabili sembra più intuitivo per me. ma sarei interessato anche a un confronto delle prestazioni. – msparer

+0

sì, non pensavo che ci sarebbe stata molta differenza, ma grazie per i risultati del test :) –