我想知道是否存在(可能更好的方式)按IN()子句中的值的顺序排序。
问题是我有2个查询,一个获取所有ID,第二个查询所有信息。第一个创建我想要第二个订购的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()子句的顺序返回结果。
我找到的一个解决方案是将所有ID放入带有自动递增字段的临时表中,然后将其加入第二个查询。
有更好的选择吗?
注意:由于第一个查询是“由用户”运行而第二个是在后台进程中运行,因此无法使用子查询将2合1查询组合。
我正在使用MySQL,但我认为让它注意到其他数据库的选项可能也很有用。
答案 0 :(得分:175)
使用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()
函数中,则可以按照相同的顺序执行此操作。
答案 1 :(得分:14)
请参阅以下如何获取排序数据。
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
答案 2 :(得分:11)
浮现在脑海中的两个解决方案:
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()
或类似的东西)
答案 3 :(得分:5)
获取排序数据的答案。
SELECT ...
FROM ...
ORDER BY FIELD(user_id,5,3,2,...,50) LIMIT 10
答案 4 :(得分:5)
如果您想使用 MS SQL Server 2008 + 中的查询输入的值对查询进行任意排序,可以通过动态创建表并执行类似的连接来完成(使用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语句替换为执行相同操作的其他语句,但在ANSI SQL中,那么这应该适用于任何SQL数据库。
注意:强> 查询大于100的记录集时,创建的表中的第二列(orderTbl.orderIdx)是必需的。我最初没有orderIdx列,但发现结果集大于100我必须按该列显式排序;无论如何,在SQL Server Express 2014中。
答案 5 :(得分:4)
IN子句描述了一组值,并且集合没有顺序。
您的解决方案通过联接然后在display_order
列进行排序是最接近正确的解决方案;其他任何东西都可能是特定于DBMS的黑客(或者在标准SQL中使用OLAP函数做一些事情)。当然,连接是最接近可移植的解决方案(尽管生成具有display_order
值的数据可能会有问题)。请注意,您可能需要选择排序列;曾经是标准SQL中的一个要求,尽管我相信它在不久前已经放宽了(可能早在SQL-92之前)。
答案 6 :(得分:3)
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)
工作真的很棒
答案 7 :(得分:2)
使用MySQL FIND_IN_SET功能:
SELECT *
FROM table_name
WHERE id IN (..,..,..,..)
ORDER BY FIND_IN_SET (coloumn_name, .., .., ..);
答案 8 :(得分:2)
对于Oracle,John使用instr()函数的解决方案可行。这是有点不同的解决方案 -
SELECT id
FROM table1
WHERE id IN (1, 20, 45, 60)
ORDER BY instr('1, 20, 45, 60', id)
答案 9 :(得分:1)
我的第一个想法是写一个查询,但你说这是不可能的,因为一个是由用户运行而另一个是在后台运行。如何存储要从用户传递到后台进程的ID列表?为什么不将它们放在带有列的临时表中以表示订单。
那怎么样:
答案 10 :(得分:1)
我认为你应该设法存储你的数据,你只需要做一个连接,这将是完美的,所以没有黑客和复杂的事情发生。
我有一个“最近播放”的音轨ID列表,在SQLite上我只是这样做:
SELECT * FROM recently NATURAL JOIN tracks;
答案 11 :(得分:0)
试一试:
SELECT name, description, ...
WHERE id IN
(SELECT id FROM table1 WHERE...)
ORDER BY
(SELECT display_order FROM table1 WHERE...),
(SELECT name FROM table1 WHERE...)
WHERE可能需要稍微调整才能使相关的子查询正常工作,但基本原则应该是合理的。