UNION和UNION ALL是 SQL 中用于合并两个或多个查询结果集的操作符。它们的基本作用相同,但在去重和性能上有关键区别。
一、核心区别
| 特性 | UNION | UNION ALL |
|---|---|---|
| 去重 | ✅ 会去除重复行 | ❌ 保留所有行(包括重复) |
| 性能 | 较慢(需要排序去重) | 更快(直接合并) |
| 使用场景 | 需要唯一结果集 | 不关心重复 / 已知不会重复 |
记住一句话:
UNION ALL是直接拼接,UNION是拼接后再去重。
二、示例说明
假设有两张表:
表 A:
text
id | name ----|------ 1 | 张三 2 | 李四
表 B:
text
id | name ----|------ 2 | 李四 3 | 王五
UNION ALL(保留重复)
sql
SELECT id, name FROM A UNION ALL SELECT id, name FROM B;
结果:
text
1 | 张三 2 | 李四 2 | 李四 ← 重复保留 3 | 王五
UNION(去重)
sql
SELECT id, name FROM A UNION SELECT id, name FROM B;
结果:
text
1 | 张三 2 | 李四 3 | 王五
三、使用限制和注意事项
| 规则 | 说明 |
|---|---|
| 列数必须相同 | 所有查询的SELECT列数必须一致 |
| 列类型必须兼容 | 对应列的数据类型必须能隐式转换 |
| 列名以第一个查询为准 | 最终结果集的列名由第一个SELECT决定 |
ORDER BY只能放在最后 | 不能对单个子查询排序,只能对整个结果集排序 |
LIMIT只能放在最后 | 同上 |
四、常见写法
1. 合并查询结果
sql
SELECT id, name FROM table_a UNION ALL SELECT id, name FROM table_b ORDER BY id DESC; -- 对整个结果集排序
2. 合并后分页
sql
SELECT id, name FROM ( SELECT id, name FROM table_a UNION ALL SELECT id, name FROM table_b ) t LIMIT 10 OFFSET 0;
3. 组合UNION和WHERE
sql
SELECT id, name FROM table_a WHERE status = 1 UNION ALL SELECT id, name FROM table_b WHERE status = 1;
五、性能对比
| 操作 | 执行计划 |
|---|---|
UNION ALL | 直接 Append(追加)结果集,最快 |
UNION | Append + Sort + Unique(排序去重),多消耗 CPU 和内存 |
建议:如果确认数据不会重复,或者业务上允许重复,尽量使用UNION ALL。
六、在 MyBatis-Plus / JPA 中使用
MyBatis-Plus(XML)
xml
<select id="unionExample" resultType="com.seazon.cloud.entity.Driver"> SELECT id, name FROM driver_info UNION ALL SELECT id, name FROM driver_history </select>
JPA(原生 SQL)
java
@Query(value = "SELECT id, name FROM driver_info " + "UNION ALL " + "SELECT id, name FROM driver_history", nativeQuery = true) List<Object[]> unionQuery();
七、UNION与JOIN的区别
| 对比 | UNION | JOIN |
|---|---|---|
| 作用 | 上下合并行 | 左右关联列 |
| 结果 | 行数增加 | 列数增加 |
| 关联 | 不需要关联条件 | 需要ON条件 |
图示:
text
UNION: JOIN: 表A 行 表A 列 表B 列 表A 行 → 表A 行 表B 行 ← 横向扩展 表B 行 ↑ 表A 行 表B 行 表B 行 纵向扩展
八、总结
| 需求 | 推荐使用 |
|---|---|
| 结果集不允许重复 | UNION |
| 结果集允许重复 / 已知无重复 | UNION ALL(优先) |
| 需要排序 | ORDER BY放在最后 |
| 需要分页 | 先UNION再套一层LIMIT |