sql中的并(UNION)、交(INTERSECT)、差(MINUS)

这三个操作是 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 对合并后的结果排序,示例:

    sql 复制代码
    SELECT 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"的行

五、避坑关键

  1. 字段一致性:所有集合操作必须保证两个结果集的字段数、类型、顺序完全一致,否则报错;
  2. NULL 值处理 :NULL 不参与集合匹配(如 NULL = NULL 为 false),需用 IS NULL 单独判断;
  3. 性能优先
    • 并集:优先用 UNION ALL 而非 UNION
    • 交集/差集:大表用 JOIN/EXISTS,小表用 IN
  4. MySQL 替代方案:记牢"交集用 JOIN,差集用 LEFT JOIN + IS NULL",这是 MySQL 中最通用的写法。

总结

  1. UNION/UNION ALL:合并结果集,UNION 去重、UNION ALL 保留所有行(性能优),MySQL 原生支持;
  2. INTERSECT(交集):取共同行,MySQL 需用 JOIN/IN/EXISTS 模拟;
  3. MINUS/EXCEPT(差集):取"仅在A/仅在B"的行,MySQL 需用 LEFT JOIN + IS NULL 模拟;
  4. 核心前提:所有集合操作的两个结果集必须字段数、类型、顺序一致。

这些集合操作是 SQL 数据分析的常用工具,尤其在报表统计、数据对比场景中高频使用,重点掌握 MySQL 的替代实现方式即可。

相关推荐
小高不会迪斯科7 小时前
CMU 15445学习心得(二) 内存管理及数据移动--数据库系统如何玩转内存
数据库·oracle
e***8907 小时前
MySQL 8.0版本JDBC驱动Jar包
数据库·mysql·jar
l1t7 小时前
在wsl的python 3.14.3容器中使用databend包
开发语言·数据库·python·databend
失忆爆表症9 小时前
03_数据库配置指南:PostgreSQL 17 + pgvector 向量存储
数据库·postgresql
AI_56789 小时前
Excel数据透视表提速:Power Query预处理百万数据
数据库·excel
SQL必知必会10 小时前
SQL 窗口帧:ROWS vs RANGE 深度解析
数据库·sql·性能优化
Gauss松鼠会10 小时前
【GaussDB】GaussDB数据库开发设计之JDBC高可用性
数据库·数据库开发·gaussdb
+VX:Fegn089510 小时前
计算机毕业设计|基于springboot + vue鲜花商城系统(源码+数据库+文档)
数据库·vue.js·spring boot·后端·课程设计
识君啊11 小时前
SpringBoot 事务管理解析 - @Transactional 的正确用法与常见坑
java·数据库·spring boot·后端
一个天蝎座 白勺 程序猿11 小时前
破译JSON密码:KingbaseES全场景JSON数据处理实战指南
数据库·sql·json·kingbasees·金仓数据库