UNION 运算符,用最简单的话说就是:
把两个查询的结果“上下堆叠”成一张表。
就像把两张纸的名单,上下拼成一张长名单。
一句话理解
| 操作 | 效果 |
|---|---|
UNION | 上下拼接 + 去重 |
UNION ALL | 上下拼接 + 不去重 |
举个具体例子
表A:2024年销售员
| name |
|---|
| 张三 |
| 李四 |
| 王五 |
表B:2025年销售员
| name |
|---|
| 李四 |
| 赵六 |
| 孙七 |
执行 UNION
sql
SELECT name FROM 表AUNIONSELECT name FROM 表B;
结果:
| name |
|---|
| 张三 |
| 李四 |
| 王五 |
| 赵六 |
| 孙七 |
李四只出现一次(去重了)
执行 UNION ALL
sql
SELECT name FROM 表AUNION ALLSELECT name FROM 表B;
结果:
| name |
|---|
| 张三 |
| 李四 |
| 王五 |
| 李四 |
| 赵六 |
| 孙七 |
李四出现两次(不去重)
UNION 的核心规则
| 规则 | 说明 |
|---|---|
| 列数必须相同 | 第一个查询选3列,第二个也必须选3列 |
| 列的顺序对应 | 按位置匹配,不是按列名 |
| 列的数据类型要兼容 | 不能一个选数字,一个选文字 |
| 列名由第一个查询决定 | 第二个查询的列名会被忽略 |
什么时候用 UNION?
✅ 典型场景
合并不同月份的销售记录
sql
SELECT 订单号 FROM 一月订单UNION ALLSELECT 订单号 FROM 二月订单
把两个没有关联的表拼在一起
sql
SELECT 员工名, '员工' AS 类型 FROM 员工表UNIONSELECT 客户名, '客户' AS 类型 FROM 客户表
统计“出现过”的独立值(用 UNION 去重)
sql
-- 哪些人要么买过东西,要么发过评论SELECT user_id FROM 订单表UNIONSELECT user_id FROM 评论表
❌ 不合适的场景
两个表需要左右拼接(应该用
JOIN)数据量巨大且不需要去重(用
UNION ALL更快)
UNION vs UNION ALL 性能区别
| UNION | UNION ALL | |
|---|---|---|
| 去重 | ✅ 会 | ❌ 不会 |
| 排序 | 需要排序去重 | 不需要 |
| 速度 | 慢 | 快 |
| 内存 | 更多 | 更少 |
经验法则:
能确定没重复 → 用
UNION ALL需要去重 → 用
UNION不确定 + 数据量大 → 先用
UNION ALL,后面再单独去重
一个容易踩的坑
sql
-- ❌ 列数不同,报错SELECT id, name FROM 表AUNIONSELECT name FROM 表B;-- ✅ 列数相同SELECT id, name FROM 表AUNIONSELECT id, name FROM 表B;
sql
-- ❌ 顺序不对,语义错误SELECT name, age FROM 表AUNIONSELECT age, name FROM 表B; -- 会把age拼到name列下面
类比理解
JOIN:左右拼(把两列的桌子拼成一列宽的桌子)UNION:上下拼(把两列的桌子拼成一列长的桌子)
text
JOIN: 表A 表B 1 一 2 二 ↓ 表A.1 | 表B.一 表A.2 | 表B.二 UNION: 表A 表B 1 一 2 二 ↓ 1 2 一 二
一句话总结
UNION是“竖着拼”,JOIN是“横着连”。UNION ALL更快但不去重,UNION去重但更慢。
记不住没关系,你只需要记住:
想把两个长得差不多的名单/记录接在一起,就用 UNION