union语法的使用前提是什么_mysql结果合并语法

来源:这里教程网 时间:2026-02-28 20:36:39 作者:

UNION 要求列数和对应类型必须兼容

MySQL 的

UNION
不是简单拼接两组结果,它强制要求左右两个
SELECT
语句返回的列数完全相同,且对应位置的列在隐式转换下能兼容。比如
INT
VARCHAR
可能被转成字符串合并,但
JSON
BLOB
在某些版本会报错。

列名以第一个
SELECT
为准,后续的列名会被忽略
不能对单个子查询加
ORDER BY
,除非配合
LIMIT
(否则语法报错)
想按整结果排序,
ORDER BY
必须写在最后一个子句之后,且引用的是第一个
SELECT
的字段别名或位置序号(如
ORDER BY 1

UNION vs UNION ALL:去重开销很实在

默认的

UNION
会自动去重,MySQL 内部要对合并后的临时结果做排序 + 去重操作,数据量大时明显拖慢;而
UNION ALL
直接追加,零额外开销。如果你能确认两边结果天然无交集(比如查不同状态的订单、不同日期的分区表),就该用
UNION ALL

UNION
等价于
UNION DISTINCT
,显式写出更易读
去重逻辑基于所有列的全值比较,不是主键或某几列 如果只想要某几列去重,得在外层套
SELECT DISTINCT
,不能靠
UNION
实现

子查询里不能直接用 LIMIT(除非配 ORDER BY)

这是新手高频报错点:

(SELECT * FROM t1 LIMIT 1) UNION (SELECT * FROM t2)
会提示
This version of MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery'
—— 实际上不是 LIMIT 本身的问题,而是 MySQL 限制了带
LIMIT
的子查询出现在
UNION
左右两侧(5.7+ 仍存在此限制)。

绕过方法:把带
LIMIT
的查询包一层派生表,例如
(SELECT * FROM (SELECT * FROM t1 ORDER BY id LIMIT 1) AS tmp)
注意:派生表必须有别名,否则语法错误 如果只是想取合并后的前 N 条,直接在
UNION
整体后加
LIMIT
即可
SELECT id, name FROM users WHERE status = 1
UNION ALL
SELECT id, name FROM users WHERE status = 2
ORDER BY id DESC
LIMIT 10;

NULL 和隐式类型转换容易引发意料外结果

当两个

SELECT
中同一列一边是
INT
、另一边是
VARCHAR
,MySQL 会尝试转成一个公共类型(通常是字符串),这时数值
0
和字符串
'0'
会被认为相等,
UNION
去重时可能意外合并;同理,
NULL
和空字符串在某些字符集下也可能被当作相同值处理。

显式用
CAST()
CONVERT()
统一类型最稳妥
测试时用
UNION ALL
先看原始数据,再切回
UNION
观察去重效果
涉及时间字段时,注意
DATETIME
TIMESTAMP
在时区处理上的差异可能导致表面相同实则不等

实际用的时候,先跑通

UNION ALL
,再决定是否需要去重;列对齐和类型一致性,比写法“漂亮”重要得多。

相关推荐