Documentation Home

13.2.10.3 UNION 子句

SELECT ...
UNION [ALL | DISTINCT] SELECT ...
[UNION [ALL | DISTINCT] SELECT ...]

UNION将多个SELECT语句的结果组合成一个结果集。例子:

mysql> SELECT 1, 2;
+---+---+
| 1 | 2 |
+---+---+
| 1 | 2 |
+---+---+
mysql> SELECT 'a', 'b';
+---+---+
| a | b |
+---+---+
| a | b |
+---+---+
mysql> SELECT 1, 2 UNION SELECT 'a', 'b';
+---+---+
| 1 | 2 |
+---+---+
| 1 | 2 |
| a | b |
+---+---+
结果集列名和数据类型

结果集的列名UNION 取自第一条 SELECT语句的列名。

SELECT每条语句 相应位置列出的选定列 应具有相同的数据类型。例如,第一个语句选择的第一列应该与其他语句选择的第一列具有相同的类型。如果对应SELECT列的数据类型不匹配,则 UNION结果中列的类型和长度将考虑所有 SELECT语句检索的值。例如,考虑以下内容,其中列长度不受第一个值的长度限制 SELECT

mysql> SELECT REPEAT('a',1) UNION SELECT REPEAT('b',20);
+----------------------+
| REPEAT('a',1)        |
+----------------------+
| a                    |
| bbbbbbbbbbbbbbbbbbbb |
+----------------------+
联合表

从 MySQL 8.0.19 开始,您还可以 在 任何可以使用等效语句的地方使用TABLE语句或 语句。假设表和 被创建和填充如下所示: VALUESUNIONSELECTt1t2

CREATE TABLE t1 (x INT, y INT);
INSERT INTO t1 VALUES ROW(4,-2),ROW(5,9);

CREATE TABLE t2 (a INT, b INT);
INSERT INTO t2 VALUES ROW(1,2),ROW(3,4);

如前所述,忽略以 开头的查询输出中的列名, VALUES以下所有 UNION查询都会产生相同的结果:

SELECT * FROM t1 UNION SELECT * FROM t2;
TABLE t1 UNION SELECT * FROM t2;
VALUES ROW(4,-2), ROW(5,9) UNION SELECT * FROM t2;
SELECT * FROM t1 UNION TABLE t2;
TABLE t1 UNION TABLE t2;
VALUES ROW(4,-2), ROW(5,9) UNION TABLE t2;
SELECT * FROM t1 UNION VALUES ROW(4,-2),ROW(5,9);
TABLE t1 UNION VALUES ROW(4,-2),ROW(5,9);
VALUES ROW(4,-2), ROW(5,9) UNION VALUES ROW(4,-2),ROW(5,9);

要强制列名相同, VALUES请将左侧的 包裹在 a 中 SELECT并使用别名,如下所示:

SELECT * FROM (VALUES ROW(4,-2), ROW(5,9)) AS t(x,y)
  UNION TABLE t2;
SELECT * FROM (VALUES ROW(4,-2), ROW(5,9)) AS t(x,y)
  UNION VALUES ROW(4,-2),ROW(5,9);
UNION DISTINCT 和 UNION ALL

默认情况下,重复行会从 UNION结果中删除。optional DISTINCT关键字具有相同的效果,但使其显式化。使用可选ALL 关键字,不会发生重复行删除,结果包括所有 SELECT语句中的所有匹配行。

您可以在同一个查询 中混合使用UNION ALL和。UNION DISTINCT处理混合 UNION类型时,DISTINCT联合会覆盖 ALL其左侧的任何联合。DISTINCT联合可以通过 using 显式生成,也可以通过不 带任何后续 关键字或关键字 的 usingUNION DISTINCT隐式 生成。UNIONDISTINCTALL

在 MySQL 8.0.19 及更高版本中,当在联合中使用一个或多个语句 时UNION ALL, 工作方式相同。UNION DISTINCTTABLE

联合中的 ORDER BY 和 LIMIT

要将ORDER BYor LIMIT子句应用于 individual SELECTSELECT请将 the 括起来并将子句放在括号内:

(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);

使用ORDER BYfor 单个 SELECT语句并不意味着行在最终结果中出现的顺序,因为UNION默认情况下会生成一组无序的行。因此,ORDER BY 在此上下文中通常与 结合使用 LIMIT来确定要为 检索的所选行的子集 SELECT,即使它不一定会影响这些行在最终 UNION结果中的顺序。如果ORDER BY没有出现LIMIT在 a 中 SELECT,它会被优化掉,因为它在任何情况下都没有效果。

要使用ORDER BYor LIMIT子句对整个 UNION结果进行排序或限制,请将各个SELECT语句括起来并将ORDER BYor 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;

没有括号的语句等同于刚才显示的带括号的语句。

从 MySQL 8.0.19 开始,您可以按照刚才显示的相同方式在联合中使用ORDER BYand LIMITwith ,请TABLE记住TABLE 不支持WHERE子句。

这种ORDER BY不能使用包含表名(即 tbl_name.col_name 格式的名称)的列引用。SELECT相反,在第一条语句中提供列别名 并在ORDER BY. (或者,在ORDER BY使用其列位置中引用该列。但是,不推荐使用列位置。)

此外,如果要排序的列有别名,则ORDER BY子句必须引用别名,而不是列名。以下语句中的第一个是允许的,但第二个语句会因 Unknown column 'a' in 'order clause'错误而失败:

(SELECT a AS b FROM t) UNION (SELECT ...) ORDER BY b;
(SELECT a AS b FROM t) UNION (SELECT ...) ORDER BY a;

要使UNION结果中的行由逐行检索的行集组成,请在每行 SELECT中选择一个附加列 SELECT用作排序列,并ORDER BY在最后一列之后添加对该列进行排序的SELECT

(SELECT 1 AS sort_col, col1a, col1b, ... FROM t1)
UNION
(SELECT 2, col2a, col2b, ... FROM t2) ORDER BY sort_col;

要另外维护单个结果中的排序顺序 ,请向子句 SELECT添加辅助列:ORDER BY

(SELECT 1 AS sort_col, col1a, col1b, ... FROM t1)
UNION
(SELECT 2, col2a, col2b, ... FROM t2) ORDER BY sort_col, col1a;

使用附加列还可以让您确定 SELECT每一行来自哪一列。额外的列也可以提供其他标识信息,例如指示表名的字符串。

联合限制

在 aUNION中, SELECT语句是普通的 select 语句,但有以下限制:

  • HIGH_PRIORITY在第一个 SELECT没有效果。 HIGH_PRIORITY在任何后续 SELECT产生语法错误。

  • 只有最后一条SELECT 语句可以使用INTO子句。但是,整个UNION 结果将写入INTO输出目标。

从 MySQL 8.0.20 开始,这两个 UNION包含的变体 INTO已被弃用,您应该期望在未来的 MySQL 版本中删除对它们的支持:

  • 在查询表达式的尾随查询块中,使用 INTObeforeFROM 会产生警告。例子:

    ... UNION SELECT * INTO OUTFILE 'file_name' FROM table_name;
  • 在查询表达式的带括号的尾随块中,使用INTO(无论其相对于 的位置如何FROM)会产生警告。例子:

    ... UNION (SELECT * INTO OUTFILE 'file_name' FROM table_name);

    这些变体已被弃用,因为它们令人困惑,就好像它们从命名表而不是整个查询表达式 (the UNION) 中收集信息一样。

UNIONORDER BY子句中 带有聚合函数的查询会被ER_AGGREGATE_ORDER_FOR_UNION 错误拒绝。例子:

SELECT 1 AS foo UNION SELECT 2 ORDER BY MAX(1);
MySQL 8.0 中的 UNION 处理与 MySQL 5.7 的对比

在 MySQL 8.0 中,解析器规则 SELECTUNION被重构为更加一致(相同的SELECT 语法在每个这样的上下文中统一应用)并减少重复。与 MySQL 5.7 相比,这项工作产生了几个用户可见的效果,可能需要重写某些语句:

  • NATURAL JOIN允许可选 INNER关键字 ( NATURAL INNER JOIN),符合标准 SQL。

  • ... JOIN ... JOIN ... ON ... ON根据标准 SQL, 允许不带括号的右深度连接(例如, )。

  • STRAIGHT_JOIN现在允许一个 USING子句,类似于其他内部联接。

  • 解析器接受查询表达式周围的括号。例如,(SELECT ... UNION SELECT ...)是允许的。另见 第 13.2.10.6 节,“带括号的查询表达式”

  • 解析器更好地符合文档中允许放置的SQL_CACHESQL_NO_CACHE查询修饰符。

  • 联合的左侧嵌套,以前只允许在子查询中使用,现在可以在顶级语句中使用。例如,这个声明现在被认为是有效的:

    (SELECT 1 UNION SELECT 1) UNION SELECT 1;
  • 锁定子句 ( FOR UPDATE, LOCK IN SHARE MODE) 只允许在非UNION查询中使用。这意味着括号必须用于SELECT 包含锁定子句的语句。此声明不再被接受为有效:

    SELECT 1 FOR UPDATE UNION SELECT 1 FOR UPDATE;

    相反,写这样的声明:

    (SELECT 1 FOR UPDATE) UNION (SELECT 1 FOR UPDATE);