UNION 和 ORDER BY 的使用不正确?

Posted

技术标签:

【中文标题】UNION 和 ORDER BY 的使用不正确?【英文标题】:Incorrect usage of UNION and ORDER BY? 【发布时间】:2011-10-07 15:22:59 【问题描述】:

如何在mysql中使用unionorder by

select * from _member_facebook 
inner join _member_pts 
ON _member_facebook._fb_owner=_member_pts._username 
where _member_facebook._promote_point = 9 
ORDER BY RAND() limit 2 
UNION ALL
select * from _member_facebook 
inner join _member_pts 
ON _member_facebook._fb_owner=_member_pts._username 
where _member_facebook._promote_point = 8 limit 3

给我错误

#1221 - Incorrect usage of UNION and ORDER BY

有人可以帮忙吗?

【问题讨论】:

【参考方案1】:

在查询中使用 Order by 和 limit 子句时,使用括号解决了我的问题。我的要求是在特定条件下获取表格的顶部和底部行,以下代码对我有用:

(SELECT column1, column2
FROM table1
ORDER BY column1, column2
LIMIT 1)

UNION

(SELECT column1, column2
FROM table2
ORDER BY column1, column2 
LIMIT 1)

【讨论】:

【参考方案2】:

我认为如果您使用 order by 或 limit 或同时使用两者,则必须使用括号。我尝试通过在不带括号的情况下互换使用限制和顺序来处理查询,但查询不起作用。它只有在添加括号后才有效。

【讨论】:

【参考方案3】:

try () 我觉得像

(SELECT  CITY,LENGTH(CITY) FROM STATION WHERE LENGTH(CITY)=(SELECT MIN(LENGTH(CITY)) FROM STATION) ORDER BY CITY LIMIT 1) 
UNION ALL
(SELECT  CITY,LENGTH(CITY) FROM STATION WHERE LENGTH(CITY)=(SELECT MAX(LENGTH(CITY)) FROM STATION) ORDER BY CITY LIMIT 1);

【讨论】:

【参考方案4】:

正确的是:

(SELECT *
   FROM _member_facebook
   INNER JOIN _member_pts ON _member_facebook._fb_owner=_member_pts._username
   WHERE _member_facebook._promote_point = 9 LIMIT 2)
UNION ALL
  (SELECT *
   FROM _member_facebook
   INNER JOIN _member_pts ON _member_facebook._fb_owner=_member_pts._username
   WHERE _member_facebook._promote_point = 8 LIMIT 3)
ORDER BY 1

【讨论】:

【参考方案5】:

说明:

了解其工作原理对于避免在类似用例中出现“陷阱”非常重要。注意union的语法有点“特殊”:

子语句union all 子语句union all 子语句 [order by-clause] [limit-clause]

其中“子语句”可以选择由() 包围。一些工作示例:

select 1 union all (select 2);
select 1 union all  select 2  union all (select 3);
select 1 union all (select 2) union all  select 3;
select 1 union all (select 2) union all (select 3);
select 1 union all (select 2) union all (select 3) union all  select 4;
select 1 union all (select 2) union all  select 3  union all (select 4);

但是,如果您用大括号将第一个“子语句”括起来,则您必须将所有其他“子语句”括起来 em>"s 带大括号:

(select 1) union all (select 2) union all (select 3);

(注意上面的点在official docs中没有提到。)

不这样做是语法错误:

mysql> (select 1) union all select 2; -- error because not all "substatement"s are braced
ERROR 1064 (42000): You have an error in your SQL syntax; check the...
mysql> (select 1) union all (select 2) union all  select 3; -- error because not all "substatement"s are braced
ERROR 1064 (42000): You have an error...
mysql> (select 1) union all  select 2  union all (select 3); -- error because not all "substatement"s are braced
ERROR 1064 (42000): You have an error...

接下来,每个“子语句”可以包含wheregroup byhavingjoinlimit,但不能包含order by

如果您想使用order by,则包含order by 的“子语句”必须用大括号括起来。 (这意味着它们不再是可选的。)

现在,如果我们再看一下语法:

子语句union all 子语句union all 子语句 [order by-clause] [limit-clause]

我们可以看到整个union 语句以可选的order by / limit 结尾。这两个关键字适用于整个union 语句,而不仅仅是最后一个“子语句”:

mysql> select 1
    -> union all
    -> select 2 limit 1;
+---+
| 1 |
+---+
| 1 |
+---+
1 row in set (0.00 sec)

mysql>

我们之前已经提到,limit 关键字也可以应用于单个“子语句”:

mysql> select 1 limit 1
    -> union all
    -> select 2;
+---+
| 1 |
+---+
| 1 |
| 2 |
+---+
2 rows in set (0.00 sec)

mysql>

如果您想将limit 应用于最后一个“子语句”(而不是整个union 语句),您必须将最后一个“substatement" 带大括号:

mysql> select 1
    -> union all
    -> (select 2 limit 1);
+---+
| 1 |
+---+
| 1 |
| 2 |
+---+
2 rows in set (0.00 sec)

mysql>

要将limit 应用于最后一个“子语句应用于整个union 语句,请使用:

mysql> select 1
    -> union all
    -> (select 2 limit 1)limit 1;
+---+
| 1 |
+---+
| 1 |
+---+
1 row in set (0.00 sec)

mysql>

order by也一样:

mysql> select 1
    -> union all
    -> (select 2 order by 1)order by 1;
+---+
| 1 |
+---+
| 1 |
| 2 |
+---+
2 rows in set (0.00 sec)

mysql>

但请注意,将order by 应用于“子语句”是没有意义的,因为文档明确声明 order by 只是保证 (cf.) 在应用于整个 union 语句时工作:

 –§–  ..将ORDER BY 用于单个SELECT 语句并不意味着行在最终结果中出现的顺序。

order by 在“子语句”中有意义的唯一方法是将它与 limit 结合使用:

 –§–  ..在这种情况下 ORDER BY 的使用通常与 LIMIT 结合使用,因此它用于确定要为 SELECT 检索的选定行的子集,即使它不一定会影响这些行在最终 UNION 结果中的顺序。

此外,如果您想将select <strong><em>into</em></strong>union 结合使用,则需要注意更多“陷阱”。请参阅issue 32858 了解此内容。

【讨论】:

【参考方案6】:

带括号:

(
    SELECT *
    FROM _member_facebook
    INNER JOIN _member_pts
    ON _member_facebook._fb_owner         =_member_pts._username
    WHERE _MEMBER_FACEBOOK._PROMOTE_POINT = 9
    ORDER BY RAND()
    LIMIT 2
)
UNION ALL
(
    SELECT *
    FROM _MEMBER_FACEBOOK
    INNER JOIN _MEMBER_PTS
    ON _MEMBER_FACEBOOK._FB_OWNER         =_MEMBER_PTS._USERNAME
    WHERE _MEMBER_FACEBOOK._PROMOTE_POINT = 8
    LIMIT 3
)

也就是说,MySQL 在外部子句中保留内部排序并不是强制性的——尽管它可能会这样做,因为它无论如何都需要对行进行排序以计算相应的 @987654322 @ 子句。

【讨论】:

是的,我也错过了括号,并添加它修复它【参考方案7】:

尝试:

(
  select 
    * 
  from 
     _member_facebook 
   inner join 
     _member_pts 
   ON 
     _member_facebook._fb_owner=_member_pts._username 
  where 
    _member_facebook._promote_point = 9 
  ORDER BY RAND() 
  limit 2
) 
UNION ALL
(
  select 
    * 
  from 
    _member_facebook 
   inner join 
    _member_pts 
   ON 
     _member_facebook._fb_owner=_member_pts._username 
  where 
    _member_facebook._promote_point = 8 
  limit 3
)

不过,我认为您应该将ORDER BY 子句放在第二个查询的末尾

【讨论】:

以上是关于UNION 和 ORDER BY 的使用不正确?的主要内容,如果未能解决你的问题,请参考以下文章

ORACLE 两个order by的SQL使用 UNION 或者 UNION ALL 报错 ORA-00933:sql命令未正确结束

oracle 两个sql带有order by的使用union/union all的时候报错 'ORA-00933:sql命令未正确结束' 处理办法

UNION ALL、UNION与ORDER BY

MySQL中Union子句不支持order by的解决方法

Mysql:使用union all时使用order by和limit到单独的查询

UNION ALL、TEXT 字段和 ORDER BY 错误