这三个操作是 SQL 中处理"数据集之间关系"的核心,本质是对两个查询结果集做集合运算 (类似数学中的并集、交集、差集),核心要求:两个结果集的字段数、字段类型、字段顺序必须完全一致。
先准备两张结构完全相同的测试表,方便示例理解:
sql
-- 表A:一班学生
CREATE TABLE class_a (
id INT,
name VARCHAR(20)
);
INSERT INTO class_a VALUES (1, '张三'), (2, '李四'), (3, '王五');
-- 表B:二班学生(和一班有重叠)
CREATE TABLE class_b (
id INT,
name VARCHAR(20)
);
INSERT INTO class_b VALUES (2, '李四'), (3, '王五'), (4, '赵六');
一、并(UNION / UNION ALL):合并两个结果集
1. 核心定义
- UNION :合并两个结果集,自动去重(删除重复行);
- UNION ALL :合并两个结果集,保留所有行(包括重复)(性能更高,优先用)。
2. 语法与示例
sql
-- 1. UNION(去重):合并一班和二班学生,重复的只保留一次
SELECT id, name FROM class_a
UNION
SELECT id, name FROM class_b;
-- 结果(4行,去重)
/*
id | name
1 | 张三
2 | 李四
3 | 王五
4 | 赵六
*/
-- 2. UNION ALL(不去重):保留所有行,包括重复的李四、王五
SELECT id, name FROM class_a
UNION ALL
SELECT id, name FROM class_b;
-- 结果(6行,保留重复)
/*
id | name
1 | 张三
2 | 李四
3 | 王五
2 | 李四
3 | 王五
4 | 赵六
*/
3. 关键注意事项
-
必须保证两个查询的字段数、类型、顺序一致(如不能一个查2字段,一个查3字段);
-
性能:
UNION ALL无需去重,性能远高于UNION,能确定无重复时优先用 UNION ALL; -
排序:可在最后加
ORDER BY对合并后的结果排序,示例:sqlSELECT id, name FROM class_a UNION ALL SELECT id, name FROM class_b ORDER BY id DESC;
二、交(INTERSECT):取两个结果集的交集
1. 核心定义
返回两个结果集中同时存在的行(即"既在A里,又在B里"),类似数学中的交集。
2. 语法与注意事项
⚠️ MySQL 原生不支持 INTERSECT 关键字 ,需用 IN/EXISTS/JOIN 模拟;PostgreSQL、Oracle 等支持。
方式1:用 JOIN 模拟(推荐,性能优)
sql
-- 取一班和二班的共同学生(李四、王五)
SELECT a.*
FROM class_a a
JOIN class_b b ON a.id = b.id AND a.name = b.name;
-- 结果
/*
id | name
2 | 李四
3 | 王五
*/
方式2:用 IN 模拟(简单,适合小表)
sql
SELECT * FROM class_a
WHERE (id, name) IN (SELECT id, name FROM class_b);
方式3:用 EXISTS 模拟(适合大表)
sql
SELECT * FROM class_a a
WHERE EXISTS (
SELECT 1 FROM class_b b
WHERE a.id = b.id AND a.name = b.name
);
三、差(MINUS / EXCEPT):取两个结果集的差集
1. 核心定义
返回"在A里,但不在B里"的行(左差集),或"在B里,但不在A里"的行(右差集)。
MINUS:Oracle 关键字;EXCEPT:PostgreSQL、SQL Server 关键字;- ⚠️ MySQL 原生不支持 MINUS/EXCEPT ,需用
LEFT JOIN + IS NULL模拟。
2. 语法与示例
示例1:左差集(仅在一班,不在二班)
sql
-- 取"只在一班"的学生(张三)
SELECT a.*
FROM class_a a
LEFT JOIN class_b b ON a.id = b.id AND a.name = b.name
WHERE b.id IS NULL;
-- 结果
/*
id | name
1 | 张三
*/
示例2:右差集(仅在二班,不在一班)
sql
-- 取"只在二班"的学生(赵六)
SELECT b.*
FROM class_a a
RIGHT JOIN class_b b ON a.id = b.id AND a.name = b.name
WHERE a.id IS NULL;
-- 结果
/*
id | name
4 | 赵六
*/
四、核心对比表
| 操作 | 含义 | MySQL 支持情况 | 核心特点 |
|---|---|---|---|
| UNION | 并集(去重) | 原生支持 | 自动去重,性能稍差 |
| UNION ALL | 并集(不去重) | 原生支持 | 保留所有行,性能最优 |
| INTERSECT | 交集 | 不支持,需用 JOIN/IN/EXISTS 模拟 | 仅返回共同行 |
| MINUS/EXCEPT | 差集 | 不支持,需用 LEFT JOIN 模拟 | 仅返回"只在A/只在B"的行 |
五、避坑关键
- 字段一致性:所有集合操作必须保证两个结果集的字段数、类型、顺序完全一致,否则报错;
- NULL 值处理 :NULL 不参与集合匹配(如
NULL = NULL为 false),需用IS NULL单独判断; - 性能优先 :
- 并集:优先用
UNION ALL而非UNION; - 交集/差集:大表用
JOIN/EXISTS,小表用IN;
- 并集:优先用
- MySQL 替代方案:记牢"交集用 JOIN,差集用 LEFT JOIN + IS NULL",这是 MySQL 中最通用的写法。
总结
- UNION/UNION ALL:合并结果集,UNION 去重、UNION ALL 保留所有行(性能优),MySQL 原生支持;
- INTERSECT(交集):取共同行,MySQL 需用 JOIN/IN/EXISTS 模拟;
- MINUS/EXCEPT(差集):取"仅在A/仅在B"的行,MySQL 需用 LEFT JOIN + IS NULL 模拟;
- 核心前提:所有集合操作的两个结果集必须字段数、类型、顺序一致。
这些集合操作是 SQL 数据分析的常用工具,尤其在报表统计、数据对比场景中高频使用,重点掌握 MySQL 的替代实现方式即可。