UNION 在做什么
UNION 把两个或多个 SELECT 的结果集纵向堆叠成一个结果集,列数和类型必须兼容,列名以第一个 SELECT 为准。UNION 对合并后的结果做去重,UNION ALL 保留全部行。去重需要额外的唯一化过程,可能借助临时表或排序,因此只要业务能接受重复行,UNION ALL 在性能上总是更优的选择。
基本信息
| 适用平台 | MySQL 5.7 / 8.0、MariaDB、PostgreSQL、Oracle |
|---|---|
| 语法 | SELECT ... UNION [ALL] SELECT ... [ORDER BY ... LIMIT ...] |
| 列约束 | 各分支列数相同,类型可隐式转换 |
| 排序规则 | ORDER BY 与 LIMIT 作用于整个合并结果 |
| 默认去重 | UNION 去重,UNION ALL 不去重 |
典型使用场景
- 多张结构相似的表合并成一份列表,例如订单表与退款表按同一口径输出
- 同一张表按不同条件分段查再拼起来,避免复杂 OR 条件拖垮索引
- 归档表加在线表的历史数据查询,用 UNION ALL 顺序拼接
- 报表中把多个来源的明细合并后统一排序与分页
- 用 UNION ALL 配合标记列,区分每条数据的来源
合并与排序写法
合并与排序写法
-- 结构一致时用 UNION ALL 保留全部行
SELECT id, 'order' AS src FROM orders WHERE created_at >= CURDATE()
UNION ALL
SELECT id, 'refund' AS src FROM refunds WHERE created_at >= CURDATE();
-- 需要去重时才用 UNION
SELECT phone FROM vip UNION SELECT phone FROM trial;
-- 分支要各自限行时必须加括号,否则 LIMIT 作用于整个结果
(SELECT id FROM t1 ORDER BY id LIMIT 10)
UNION ALL
(SELECT id FROM t2 ORDER BY id LIMIT 10)
ORDER BY id DESC LIMIT 20;几种集合运算的区别
| 写法 | 作用 | 注意点 |
|---|---|---|
| UNION ALL | 纵向堆叠并保留重复行 | 性能最好,默认首选 |
| UNION | 纵向堆叠并去重 | 有唯一化成本,可能用临时表 |
| JOIN | 横向扩展列 | 与 UNION 维度不同,别混用 |
| UNION 中的 ORDER BY | 作用于最终结果 | 要限制单分支需给每个分支加括号 |
UNION 去重按整行所有列比较:只要两行在任一列上不同就不算重复,因此加了一个来源标记列后,看似相同的业务数据也不会被合并。
各分支列类型不一致时会按聚合规则隐式转换,转换为字符集或精度更高的类型,可能导致结果被截断或索引失效,输出前先显式 CAST。