我想在每个UNION ALL查询中使用ORDER BY,但我无法找出正确的语法。这就是我想要的:
(
SELECT id, user_id, other_id, name
FROM tablename
WHERE user_id = 123 AND user_in IN (...)
ORDER BY name
)
UNION ALL
(
SELECT id, user_id, other_id, name
FROM tablename
WHERE user_id = 456 AND user_id NOT IN (...)
ORDER BY name
)
编辑: 需要明确的是:我需要两个这样的有序列表,而不是一个:
1 2 3 1 2 3 4 5
非常感谢!
答案 0 :(得分:7)
你最后只使用一个ORDER BY。
联盟将两个选项转换为一个逻辑选择。 order-by适用于整个集合,而不适用于每个部分。
也不要使用任何parens。只是:
SELECT 1 as Origin, blah blah FROM foo WHERE x
UNION ALL
SELECT 2 as Origin, blah blah FROM foo WHERE y
ORDER BY Origin, z
答案 1 :(得分:7)
这样的东西应该在MySQL中起作用:
SELECT a.*
FROM (
SELECT ... FROM ... ORDER BY ...
) a
UNION ALL
SELECT b.*
FROM (
SELECT ... FROM ... ORDER BY ...
) b
但请注意,如果最外层查询中没有 ORDER BY
(或GROUP BY
)子句,则返回行的顺序为 NOT 保证。
如果需要按特定顺序返回的行,则应在最外层的查询中包含ORDER BY
。在很多用例中,我们可以在最外层的查询中使用ORDER BY
来满足结果。
但是,如果您有一个用例,您需要在第二个查询的所有行之前返回的第一个查询中的所有行,则一个选项是在每个查询中包含一个额外的鉴别器列。例如,在第一个查询中添加 ,'a' AS src
, ,'b' AS src
添加到第二个查询。
然后,最外面的查询可以包含 ORDER BY src, name
,以保证结果的顺序。
<强>后续强>
在原始查询中,优化程序会丢弃查询中的ORDER BY
;由于没有ORDER BY
应用于外部查询,MySQL可以按照自己想要的顺序自由返回行。
我的答案中的查询中的“技巧”(上图)取决于某些版本的MySQL特有的行为。
测试用例:
填充表格
CREATE TABLE foo2 (id INT PRIMARY KEY, role VARCHAR(20)) ENGINE=InnoDB;
CREATE TABLE foo3 (id INT PRIMARY KEY, role VARCHAR(20)) ENGINE=InnoDB;
INSERT INTO foo2 (id, role) VALUES
(1,'sam'),(2,'frodo'),(3,'aragorn'),(4,'pippin'),(5,'gandalf');
INSERT INTO foo3 (id, role) VALUES
(1,'gimli'),(2,'boromir'),(3,'elron'),(4,'merry'),(5,'legolas');
查询
SELECT a.*
FROM ( SELECT s.id, s.role
FROM foo2 s
ORDER BY s.role
) a
UNION ALL
SELECT b.*
FROM ( SELECT t.id, t.role
FROM foo3 t
ORDER BY t.role
) b
结果集已返回
id role
------ ---------
3 aragorn
2 frodo
5 gandalf
4 pippin
1 sam
2 boromir
3 elron
1 gimli
5 legolas
4 merry
foo2
中的行按顺序返回,然后是foo3
中的行,再次按“顺序”返回。
请注意(再次)此行为 NOT 保证。 (我们观察者的行为是MySQL如何处理内联视图(派生表)的副作用。在5.5之后的版本中,这种行为可能会有所不同。)
如果您需要按特定顺序返回的行,请为最外层查询指定 ORDER BY
子句。该顺序将适用于整个结果集。
正如我前面提到的,如果我首先需要第一个查询中的行,然后是第二个查询,我会在每个查询中包含一个“discriminator”列,然后在ORDER BY子句中包含“discriminator”列。我也会废除内联视图,并执行以下操作:
SELECT s.id, s.role, 's' AS src
FROM foo2 s
UNION ALL
SELECT t.id, t.role, 't' AS src
FROM foo3 t
ORDER BY src, role
答案 2 :(得分:4)
请勿在{{1}}内的单个ORDER BY
声明中使用SELECT
,除非您正在使用UNION
。
MySQL docs on UNION解释了为什么(强调我的):
要将ORDER BY或LIMIT应用于单个SELECT,请放置该子句 在括起SELECT的括号内:
LIMIT
但是,对单个SELECT语句使用ORDER BY意味着 没有关于行在最终结果中出现的顺序 因为UNION默认生成一组无序行。因此, 在这种情况下,ORDER BY的使用通常与 LIMIT,以便用于确定所选行的子集 检索SELECT,即使它不一定影响 最终UNION结果中这些行的顺序。 如果出现ORDER BY 在SELECT中没有LIMIT,它会被优化掉,因为它会有 无论如何都没有效果。
使用ORDER BY或LIMIT子句对整个UNION进行排序或限制 结果,括起单个SELECT语句并放置 最后一个之后的ORDER BY或LIMIT。以下示例使用两者 子句:
(SELECT a FROM t1 WHERE a=10 AND B=1 ORDER BY a LIMIT 10) UNION (SELECT a FROM t2 WHERE a=11 AND B=2 ORDER BY a LIMIT 10);
看起来像下面的(SELECT a FROM t1 WHERE a=10 AND B=1)
UNION
(SELECT a FROM t2 WHERE a=11 AND B=2)
ORDER BY a LIMIT 10;
条款可以为您提供所需的内容:
ORDER BY
答案 3 :(得分:0)
(SELECT id, user_id, other_id, name
FROM tablename
WHERE user_id = 123
AND user_in IN (...))
UNION ALL
(SELECT id, user_id, other_id, name
FROM tablename
WHERE user_id = 456
AND user_id NOT IN (...)))
ORDER BY name
您还可以简化此查询:
SELECT id, user_id, other_id, name
FROM tablename
WHERE (user_id = 123 AND user_in IN (...))
OR (user_id = 456 AND user_id NOT IN (...))