维护MySQL"IN"查询中的顺序

msp*_*msp 46 mysql sql

我有下表

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;
Run Code Online (Sandbox Code Playgroud)

然后我尝试根据主键获取记录

SELECT * FROM foo f where f.id IN (2, 3, 1);
Run Code Online (Sandbox Code Playgroud)

然后我得到以下结果

+----+--------+
| id | name   |
+----+--------+
|  1 | first  |
|  2 | second |
|  3 | third  |
+----+--------+
3 rows in set (0.00 sec)
Run Code Online (Sandbox Code Playgroud)

可以看出,结果按id排序.我想要实现的是按照我在查询中提供的顺序获取结果.鉴于此示例,它应该返回

+----+--------+
| id | name   |
+----+--------+
|  2 | second |
|  3 | third  |
|  1 | first  |
+----+--------+
3 rows in set (0.00 sec)
Run Code Online (Sandbox Code Playgroud)

Ty *_*y W 86

正如另一个答案所提到的:您发布的查询没有关于您希望结果的顺序,只是您希望得到的结果.

要订购结果,我会使用ORDER BY FIELD():

SELECT * FROM foo f where f.id IN (2, 3, 1)
ORDER BY FIELD(f.id, 2, 3, 1);
Run Code Online (Sandbox Code Playgroud)

FIELD的参数列表可以是可变长度.


Bil*_*win 23

IN()谓词中的值被视为一个集合,SQL查询返回的结果无法自动推断该集合的顺序.

通常,除非您使用ORDER BY子句指定订单,否则任何SQL查询的顺序都是任意的.

您可以使用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');
Run Code Online (Sandbox Code Playgroud)

请注意,list参数to 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)
Run Code Online (Sandbox Code Playgroud)

使用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)
Run Code Online (Sandbox Code Playgroud)

结论:在有限的测试中,两种方法都没有很大的优势.