UNION 是什么
UNION 把两个查询结果纵向拼起来:UNION 会去重,UNION ALL 保留全部行。去重需要额外排序或哈希,代价明显,所以能确定两边没有重复时优先用 UNION ALL。参与合并的每个查询列数必须相同,列名以第一个查询为准,列类型要能互相兼容。数据类型不一致时数据库会做隐式转换,可能引入意外结果。整个 UNION 结果上要排序时,ORDER BY 只能写在最后一条查询之后,作用于合并后的整体。
基本信息
| 作用 | 纵向合并多个查询的结果集 |
|---|---|
| UNION | 合并并去重,代价高于 UNION ALL |
| UNION ALL | 保留全部行,不排序不去重 |
| 列要求 | 列数相同,类型兼容,列名以第一个查询为准 |
| 排序 | ORDER BY 写在最后,作用于合并后的整体 |
| 平台差异 | MySQL 与 PostgreSQL 语法一致;PostgreSQL 另有 INTERSECT 与 EXCEPT |
典型使用场景
- 同类数据合并:把多张结构相同的归档表拼成一张结果
- 多来源查询:不同渠道的数据汇总展示
- 模拟全外连接:MySQL 不支持 FULL JOIN 时用左右连接加 UNION
- 补齐维度:把缺失的分类行人为补进结果集
- 分区表查询:把多个分区结果合并后统一排序
- 拆分复杂条件:把 OR 条件拆成两条查询再 UNION ALL
示例
示例
-- 合并并按整体排序
SELECT id, name, 'active' AS src FROM users_active
UNION ALL
SELECT id, name, 'archived' AS src FROM users_archived
ORDER BY id DESC
LIMIT 100;
-- 需要去重时用 UNION(代价更高)
SELECT email FROM users_2023
UNION
SELECT email FROM users_2024;
-- 用 UNION 模拟全外连接
SELECT a.id FROM a LEFT JOIN b ON a.id = b.a_id
UNION
SELECT b.a_id FROM a RIGHT JOIN b ON a.id = b.a_id;UNION 与 UNION ALL 对照
| 对比项 | UNION | UNION ALL |
|---|---|---|
| 是否去重 | 去重 | 不去重 |
| 是否排序 | 需要额外排序或哈希 | 直接拼接 |
| 性能 | 较慢 | 更快 |
| 适用 | 确实存在重复且要去掉 | 确定无重复或重复可接受 |
| 结果行数 | 小于等于两者之和 | 等于两者之和 |
列名由第一个查询决定,后续查询的列名只作占位;给表达式列起一个统一的别名能让结果更清晰。
在单个查询里写 ORDER BY 或 LIMIT 需要加括号,MySQL 支持把子查询加括号后参与 UNION,写之前先确认目标版本支持。
UNION 去重会把两边本来就相同的行合并掉,统计总量时会比预期少;做数据量核对时先确认业务上是否希望去重。
使用要点
- 默认用 UNION ALL,明确需要去重时才用 UNION
- 两边列顺序与类型对齐,必要处显式转换类型
- 表达式列统一别名,避免结果列名混乱
- ORDER BY 与 LIMIT 只写在最后,作用于整体结果
- 大批量合并时先把两边过滤好,减少参与排序的数据量
- 用 EXPLAIN 确认去重带来的排序或临时表是否可接受