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 的替代实现方式即可。

相关推荐
Rsun045519 分钟前
Redis中实现访问量计数
数据库·redis·缓存
天空属于哈夫克325 分钟前
自动化素材中枢:实现云端文件与外部群消息的异步同步方案
数据库·oracle
Navicat中国1 小时前
Navicat Premium Lite 正式登录鸿蒙应用市场
数据库·华为·harmonyos·navicat
Yvonne爱编码1 小时前
数据库---Day 1 数据库基础
数据库·mysql·oracle
Ricky_Theseus1 小时前
数据库关系代数 - 连接操作
linux·数据库·算法
FL4m3Y4n1 小时前
MySQL索引原理与SQL优化
android·sql·mysql
2301_793804691 小时前
定时任务专家:Python Schedule库使用指南
jvm·数据库·python
guslegend1 小时前
MySQL高手第三章
数据库·mysql
spring2997921 小时前
MySQL无法连接到本地localhost的解决办法2024.11.8
数据库·mysql·adb
落日漫游1 小时前
MySQL约束:6大核心机制详解
sql