按照SQL IN()子句中的值的顺序sorting
我想知道如果有一个IN()子句中的值的顺序sorting(可能更好的方法)。
问题是,我有2个查询,一个获取所有的ID和第二个检索所有的信息。 第一个创build我希望第二个sorting的ID的顺序。 这些ID以正确的顺序放在IN()子句中。
所以它会是(非常简化)的东西:
SELECT id FROM table1 WHERE ... ORDER BY display_order, name SELECT name, description, ... WHERE id IN ([id's from first])
问题是第二个查询不会返回结果以相同的顺序将ID放入IN()子句中。
我find的一个解决scheme是将所有的ID放入一个临时表中,然后将自动递增字段join到第二个查询中。
有更好的select吗?
注意:由于第一个查询是由“用户”运行的,第二个查询是在后台进程中运行的,因此无法使用子查询将2合并为1查询。
我正在使用MySQL,但是我认为注意其他数据库有什么选项也许是有用的。
使用MySQL的FIELD()
函数:
SELECT name, description, ... FROM ... WHERE id IN([ids, any order]) ORDER BY FIELD(id, [ids in order])
FIELD()
将返回第一个参数的索引,它等于第一个参数(除了第一个参数本身)。
FIELD('a', 'a', 'b', 'c')
将返回1
FIELD('a', 'c', 'b', 'a')
将返回3
如果将ID以相同的顺序粘贴到IN()
子句和FIELD()
函数中,这将完全符合您的要求。
请参阅以下如何获取sorting数据。
SELECT ... FROM ... WHERE zip IN (91709,92886,92807,...,91356) AND user.status=1 ORDER BY provider.package_id DESC , FIELD(zip,91709,92886,92807,...,91356) LIMIT 10
想到两个解决scheme:
-
order by case id when 123 then 1 when 456 then 2 else null end asc
-
order by instr(','||id||',',',123,456,') asc
( instr()
来自Oracle;也许你有locate()
或charindex()
或类似的东西)
IN子句描述一组值,并且集合没有顺序。
join你的解决scheme,然后在display_order
列上sorting是最接近正确的解决scheme; 其他任何东西都可能是一个特定于DBMS的破解(或者在标准SQL中使用OLAP函数做一些事情)。 当然,连接是最接近便携式的解决scheme(尽pipe使用display_order
值生成数据可能会有问题)。 请注意,您可能需要select订购栏; 过去是标准SQL中的一个要求,尽pipe我相信前一段时间(也许早在SQL-92)就已经放松了。
Ans获取sorting数据。
SELECT ... FROM ... ORDER BY FIELD(user_id,5,3,2,...,50) LIMIT 10
对于Oracle,John的解决scheme使用instr()函数。 这里有一些稍微不同的解决scheme – SELECT id FROM table1 WHERE id IN (1, 20, 45, 60) ORDER BY instr('1, 20, 45, 60', id)
SELECT ORDER_NO, DELIVERY_ADDRESS from IFSAPP.PURCHASE_ORDER_TAB where ORDER_NO in ('52000077','52000079','52000167','52000297','52000204','52000409','52000126') ORDER BY instr('52000077,52000079,52000167,52000297,52000204,52000409,52000126',ORDER_NO)
工作真的很棒
使用MySQL FIND_IN_SET函数:
SELECT * FROM table_name WHERE id IN (..,..,..,..) ORDER BY FIND_IN_SET (coloumn_name, .., .., ..);
如果您想使用MS SQL Server 2008+中查询input的值对查询进行任意sorting,则可以通过dynamic创build表格并执行类似的连接(使用OP的命名)来完成。
SELECT table1.name, table1.description ... FROM (VALUES (id1,1), (id2,2), (id3,3) ...) AS orderTbl(orderKey, orderIdx) LEFT JOIN table1 ON orderTbl.orderKey=table1.id ORDER BY orderTbl.orderIdx
如果将VALUES语句replace为执行相同操作的其他语句,但是在ANSI SQL中,则这应该适用于任何SQL数据库。
注:查询大于100左右的logging集时,创build表(orderTbl.orderIdx)中的第二列是必需的。 我本来没有一个orderIdx列,但发现结果集大于100我不得不显式sorting该列; 在SQL Server Express 2014反正。
我的第一个想法是写一个单一的查询,但你说这是不可能的,因为一个是由用户运行,另一个是在后台运行。 你如何存储从用户传递到后台进程的ID列表? 为什么不把它们放在一个临时表格中,以表示订单。
那么这个怎么样:
- 用户界面位运行并将值插入到您创build的新表中。 它会插入ID,位置和某种工作号码标识符)
- 工作号码被传递给后台进程(而不是所有的ID)
- 后台进程从第1步中的表中进行select,并join以获取所需的其他信息。 它使用WHERE子句中的作业编号和位置列的顺序。
- 后台进程完成后,根据作业标识从表中删除。
我认为你应该设法存储你的数据,你只需要简单地join,这将是完美的,所以没有黑客和复杂的事情发生。
我有例如一个“最近播放”的轨道ID列表,在SQLite上我只是做:
SELECT * FROM recently NATURAL JOIN tracks;
给这个镜头:
SELECT name, description, ... WHERE id IN (SELECT id FROM table1 WHERE...) ORDER BY (SELECT display_order FROM table1 WHERE...), (SELECT name FROM table1 WHERE...)
WHEEs可能会稍微调整一下,以使相关子查询正常工作,但基本原则应该是正确的。
我只是试图做到这一点是MS SQL Server,我们没有FIELD():
SELECT table1.id ... INNER JOIN (VALUES (10,1),(3,2),(4,3),(5,4),(7,5),(8,6),(9,7),(2,8),(6,9),(5,10) ) AS X(id,sortorder) ON X.id = table1.id ORDER BY X.sortorder
请注意,我也允许重复。