SQL 中 INTERSECT 和 EXCEPT 有什么作用?和 JOIN、NOT EXISTS 有什么区别?
简化版
INTERSECT 用于求两个查询结果的交集,EXCEPT 用于求差集。它们属于集合运算,要求两边查询列数和类型兼容。和 JOIN 不同,集合运算比较的是结果行本身;和 NOT EXISTS 相比,EXCEPT 写法更像数学集合差,但通常有去重语义,数据库支持也不完全一致。
详细版
如果要找同时出现在两个结果集中的用户,可以用 INTERSECT;如果要找在 A 结果中但不在 B 结果中的用户,可以用 EXCEPT。它们和 UNION 类似,都是把多个查询结果当集合处理。
需要注意的是,许多数据库默认 INTERSECT、EXCEPT 会去重。如果业务要求保留重复行,需要看数据库是否支持 INTERSECT ALL、EXCEPT ALL。MySQL 旧版本对这些语法支持有限,实际项目常用 JOIN 或 EXISTS 改写。
面试中要把集合运算和表连接的粒度区别讲清楚。
完整版教学
一、集合运算的前提
两边查询返回的列数要一致。
对应列的数据类型要兼容。
列名通常以第一个查询为准。
排序只能放在整体结果最后。
这是 UNION、INTERSECT、EXCEPT 的共同规则。
二、INTERSECT 示例
SELECT user_id FROM app_users
INTERSECT
SELECT user_id FROM paid_users;
结果是既在 app 用户中,又在付费用户中的用户。
这表达的是结果集交集。
三、EXCEPT 示例
SELECT user_id FROM app_users
EXCEPT
SELECT user_id FROM banned_users;
结果是在 app 用户中,但不在封禁用户中的用户。
这表达的是集合差。
四、和 JOIN 的区别
| 对比项 | 集合运算 | JOIN |
|---|---|---|
| 操作对象 | 两个查询结果集 | 两张或多张表的匹配关系 |
| 列要求 | 列数和类型兼容 | 根据 ON 条件匹配 |
| 重复行 | 常默认去重 | 可能产生重复匹配 |
| 适合语义 | 交集、差集、并集 | 取关联字段、组合信息 |
五、和 EXISTS 的区别
EXISTS 更适合表达是否存在匹配关系。
NOT EXISTS 更适合做反连接。
EXCEPT 更像对两个完整结果集做集合差。
如果只比较单列 id,两者都能表达。
如果要保留左表其他字段,NOT EXISTS 常更灵活。
六、重复行语义
集合运算的“集合”通常意味着去重。
但 SQL 表本身允许重复行。
如果业务关心重复次数,要确认是否支持 ALL 变体。
例如 EXCEPT ALL 和 EXCEPT 的结果可能不同。
面试里讲集合运算,一定要补一句“默认去重语义和数据库兼容性”。
七、误区和追问
- 误区:INTERSECT 就是 INNER JOIN。 JOIN 会按匹配关系组合列,INTERSECT 比较结果行。
- 误区:EXCEPT 和 NOT EXISTS 永远一样。 它们常可改写,但重复行、列集合和 NULL 语义要具体分析。
- 误区:所有数据库都完整支持集合运算。 不同数据库支持差异明显,尤其是
ALL变体。 - 追问:MySQL 不支持时怎么写交集? 可以用 INNER JOIN 或 EXISTS 改写。
- 追问:差集怎么避免 NOT IN 的 NULL 问题? 用
NOT EXISTS或LEFT JOIN IS NULL。 - 追问:集合运算后能 ORDER BY 吗? 可以,但通常只能对最终结果整体排序。
八、面试表达方式
先定义交集和差集。
再给单列示例。
最后说明它和 JOIN、EXISTS 的粒度、重复行语义和兼容性差异。