如何在UNION中使用ORDER BY

VOR*_*AND 7 mysql sql union

我想在每个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
)
Run Code Online (Sandbox Code Playgroud)

编辑:要明确:我需要两个这样的有序列表,而不是一个:

1 2 3 1 2 3 4 5

非常感谢你!

spe*_*593 8

像这样的东西应该在MySQL中工作:

SELECT a.*
  FROM ( 
         SELECT ...  FROM ... ORDER BY ... 
       ) a
 UNION ALL 
SELECT b.*
  FROM ( 
         SELECT ...  FROM ... ORDER BY ... 
       ) b
Run Code Online (Sandbox Code Playgroud)

不过请注意,上不存在的ORDER BY(或GROUP BY)子句的最外层查询,订单被返回的行是保证的.

如果需要按特定顺序返回的行,则应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');
Run Code Online (Sandbox Code Playgroud)

询问

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

结果集返回

    id  role     
 ------  ---------
      3  aragorn  
      2  frodo    
      5  gandalf  
      4  pippin   
      1  sam      
      2  boromir  
      3  elron    
      1  gimli    
      5  legolas  
      4  merry    
Run Code Online (Sandbox Code Playgroud)

foo2中的"按顺序"返回,然后foo3再次按"按顺序"返回行.

请注意(再次)保证此行为.(我们观察到的行为是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
Run Code Online (Sandbox Code Playgroud)


pmb*_*tin 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
Run Code Online (Sandbox Code Playgroud)


Mar*_*ams 5

除非与一起使用,否则请勿ORDER BY在中使用单个SELECT语句。UNIONLIMIT

UNION上MySQL文档解释了原因(强调我的观点):

要将ORDER BY或LIMIT应用于单个SELECT,请将子句放在包围SELECT的括号内:

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

但是,对单个SELECT语句使用ORDER BY并不意味着行在最终结果中出现的顺序,因为UNION默认情况下会产生一组无序的行。因此,在这种情况下,ORDER BY的使用通常与LIMIT结合使用,因此,它可以用来确定要为SELECT检索的所选行的子集,即使它不一定影响SELECT中的那些行的顺序。最终的UNION结果。如果ORDER BY在SELECT中没有LIMIT出现,则会对其进行优化,因为它始终无效。

要使用ORDER BY或LIMIT子句对整个UNION结果进行排序或限制,请在各个SELECT语句之间加上括号,然后将ORDER BY或LIMIT放在最后一个语句之后。下面的示例使用两个子句:

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

似乎像ORDER BY下面这样的子句将为您提供所需的内容:

ORDER BY user_id, name
Run Code Online (Sandbox Code Playgroud)