UNION ALL 和 UNION 的语法差异只在关键字本身
语法上,
UNION ALL和
UNION唯一区别就是多了一个
ALL关键字——它不改变 SELECT 结构、不新增括号、不调整列顺序,也不影响 WHERE 或 JOIN 的写法。
但这个“小改动”直接决定了 MySQL 怎么处理重复行和执行计划:
UNION会隐式加
DISTINCT+ 默认按第一列排序(除非显式禁用)
UNION ALL完全跳过去重和排序步骤,只是把两个结果集物理拼接 两者都要求:每个
SELECT的列数必须一致,对应列类型需兼容(如
INT和
BIGINT可隐式转换,但
DATE和
VARCHAR不行,得用
CAST)
列名、类型、顺序这三项必须对齐,否则直接报错
MySQL 合并时不会帮你“猜意图”,而是严格校验结构。常见报错
Error 1222: The used SELECT statements have a different number of columns就是列数不一致。
实操建议:
列名取自第一个SELECT的别名(比如
SELECT name AS title FROM a UNION SELECT username FROM b,结果列名是
title) 类型不匹配时,宁可显式
CAST也不要依赖隐式转换(例如
SELECT CAST(created_at AS CHAR) FROM orders UNION ALL SELECT update_time FROM logs) 如果表字段顺序不同(如
users(id, name)vs
admins(name, id)),必须手动调整 SELECT 列序:
SELECT id, name FROM users UNION ALL SELECT id, name FROM admins
ORDER BY 和 LIMIT 必须放在最后,且只能作用于整个结果集
你不能在每个子查询里单独写
ORDER BY来控制合并顺序——MySQL 会忽略它(除非配合
LIMIT,但仍有风险)。
正确写法只有一种结构:
SELECT id, name FROM table1 UNION ALL SELECT id, name FROM table2 ORDER BY id DESC LIMIT 20;
错误写法(会报语法错误或行为不可控):
(SELECT id, name FROM table1 ORDER BY id) UNION ALL (SELECT id, name FROM table2 ORDER BY id);
注意:
ORDER BY在
UNION/
UNION ALL中不是可选修饰,而是顶层指令,它对整个合并后结果生效。
什么时候必须用 UNION,什么时候该死守 UNION ALL
别凭感觉选。关键看数据语义和性能预期:
用UNION:跨业务系统拉取「用户列表」,怕同一人出现在多个源表中;报表去重统计唯一设备 ID 用
UNION ALL:日志表(
log_202512+
log_202601)合并查错误;过程表和归档表联合分页(确认无主键重叠) 性能陷阱:即使你加了
WHERE过滤,
UNION仍要对最终结果做全局去重,大结果集下 I/O 和临时表开销陡增 安全提示:如果用了
UNION却没检查是否真有重复数据,可能掩盖数据质量问题(比如双写导致同一条订单进了两张表)
最常被忽略的一点:UNION 的“去重”是全字段比对,不是按主键。哪怕两行只有时间戳差 1 秒,也会算作不同行——所以别指望它替你 dedupe 业务逻辑意义上的重复。
