2009-10-27 30 views
35

爲了我有如下表在MySQL的維護「IN」查詢

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; 

然後我嘗試基於主鍵

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

然後我得到以下結果

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

可以看到,結果是按id排序的。我試圖實現的是按照我在查詢中提供的順序獲取結果。鑑於這個例子,它應該返回

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

在MySQL網站上查看此答案:http://forums.mysql.com/read.php?97,210905,210918#msg-210918 - 我想你會遇到麻煩,期待在()表現得像這樣。除非明確告訴它,否則MySQL不會對結果進行排序,而且數據中沒有任何內容會按照您的要求進行排序。 – artlung 2009-10-27 15:54:48

回答

69

正如其他答案所提及的:您發佈的查詢與您希望得到結果的順序無關,只是您希望得到的結果。

要訂購您的結果,我會用ORDER BY FIELD():

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

的參數列表字段可以變長。

+1

哦,是的,這也可以。 +1 – 2009-10-27 15:56:40

+0

我很想知道在按ID排序行的一般情況下,哪種方法都有性能優勢。我一直使用FIELD(),但我已經看到了一些使用您發佈的FIND_IN_SET()方法的代碼示例。 – 2009-10-27 15:59:24

21

IN()謂詞中的值被認爲是一組,並通過SQL查詢返回的結果有沒有辦法從該組自動推斷順序。

通常,任何SQL查詢的順序都是任意的,除非ORDER BY子句指定了一個訂單。

您可以使用MySQL功能FIND_IN_SET()做你想做什麼:

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

注意,列表參數FIND_IN_SET()不喜歡的IN()參數可變長度列表。它必須是字符串文字或SET


關於性能回覆的問題:我很好奇過,所以我想這兩個FIND_IN_SET()FIELD()方法對我的StackOverflow的數據副本:

由於沒有指數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) 

索引在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) 

結論:在有限的測試中,兩種方法都沒有很大的優勢。

+1

更好,CASE'X'THEN 1,CASE'Y'THEN 2對於任意順序列 – dnagirl 2009-10-27 15:51:39

+0

感謝澄清一個 - 我去了另一個答案作爲FIELD可變參數似乎更直觀的我。但我也會對性能比較感興趣。 – msparer 2009-10-27 16:21:34

+0

是啊沒想到會有太多的差異,但感謝測試結果:) – 2009-10-27 17:32:55