MySQL INTERSECT 怎样合并两组去重结果
来源:17golang原创
时间:2026-10-22 05:45:14 358浏览 收藏
如果目标是“只保留两组查询都出现的记录”,MySQL 的 INTERSECT 比手写一层 EXISTS 更直接。它对两个查询块取交集,默认去掉重复行;如果要保留重复出现次数,才使用 INTERSECT ALL。两侧查询必须提供兼容的列结构,最终排序则放在整个集合运算之后。
官方文档:https://dev.mysql.com/doc/refman/8.4/en/set-operations.html
先把问题说成“两个结果集的共同整行”,再选择 INTERSECT。它不是把两张表拼接后再随便去重,也不是 UNION 的别名;列的位置、重复语义和 ORDER BY 的作用范围都要单独确认。
先确认 INTERSECT 要取的是交集
假设有两组用户查询:一组是当前有效会员,另一组是本月有付费记录的用户。需求是找出两组结果中都存在的 user_id,可以直接写成:
-- 两个查询块都返回 user_id,INTERSECT 只保留共同记录 SELECT user_id FROM current_members INTERSECT SELECT user_id FROM paid_users;
这里的结果是交集:只留下同时出现在 current_members 和 paid_users 中的用户。UNION 会得到两边的并集,EXCEPT 则表示左侧有、右侧没有,三者不要混用。MySQL 文档还说明,集合运算默认按去重集合处理,因此两侧各自重复出现同一个 user_id,不会让最终结果重复。

让两侧查询具备兼容的列结构
INTERSECT 比较的是两侧结果行,所以不能只看表字段名。对应位置的列数量要一致,数据类型也应能合理对应。例如下面的写法返回两列共同结果,并且最终列名来自左侧查询:
-- 两侧按相同位置返回 user_id 和 region_id SELECT user_id, region_id FROM current_members INTERSECT SELECT user_id, region_id FROM paid_users;
如果右侧把列顺序写成 region_id, user_id,即使字段名看起来相似,比较含义也已经改变。为了让结果列名稳定,通常把业务希望展示的别名写在左侧查询;右侧重点是保证对应位置的类型和含义相容。
还要注意,INTERSECT 比较的是整行。若左侧选择了 user_id, region_id,同一个用户在不同区域的两行不会因为 user_id 相同就自动合并。只想按用户去重,就只选择用户这一列,或先把两侧投影到同一粒度。
按 DISTINCT、ALL 和排序范围复查
默认的 INTERSECT 等价于显式写 INTERSECT DISTINCT,会抑制重复行。INTERSECT ALL 才会保留重复匹配的集合语义,适合两侧结果中的重复次数本身有业务含义的场景:
-- 默认去重:同一 user_id 在结果中最多出现一次 SELECT user_id FROM current_members INTERSECT DISTINCT SELECT user_id FROM paid_users; -- 保留重复行:只有确认重复次数有业务意义时才使用 ALL SELECT user_id FROM current_members INTERSECT ALL SELECT user_id FROM paid_users;
排序时,直接对最终交集排序即可:
-- ORDER BY 作用于整个 INTERSECT 结果 SELECT user_id FROM current_members INTERSECT SELECT user_id FROM paid_users ORDER BY user_id;
如果要先限制某一侧查询,再参与交集,需要给那一侧加括号,把 ORDER BY 或 LIMIT 放在括号内部;不要把末尾的整体排序误认为左侧查询的排序。集合运算混用时也要留意优先级:MySQL 文档规定 INTERSECT 的结合优先级高于 UNION 和 EXCEPT,复杂表达式最好用括号把业务意图写清楚。

发布前用四项清单复查 SQL
- 结果意图:需求是共同记录、并集还是左侧差集?共同记录才使用 INTERSECT。
- 比较粒度:两侧选择的列是否都是同一业务粒度?多选一列可能让“按用户去重”变成“按用户和区域比较”。
- 重复策略:没有明确的重复计数需求时保留默认 DISTINCT;只有需要保留重复行时才使用 ALL。
- 作用范围:整体 ORDER BY/LIMIT 放在集合运算外层,单侧 ORDER BY/LIMIT 则用括号限定查询块。
这四项确认后,INTERSECT 通常就能保持短而清楚。若集合逻辑继续变复杂,先把每个查询块单独拿出来确认列和粒度,再组合最终表达式,排错会比直接改一长串 SQL 更快。
常见问题
INTERSECT 默认会去重吗?会。MySQL 集合运算默认抑制重复行,想保留重复语义时使用 INTERSECT ALL。
两侧列名必须完全一样吗?不必,但对应位置的列数和数据类型要合理匹配,结果列名取自第一侧查询。
为什么 INTERSECT 后的 ORDER BY 没按单侧排序?未加括号时,末尾 ORDER BY 针对整个集合结果;需要限定单侧查询时,把该查询块和它的 ORDER BY/LIMIT 放进括号。
小结
MySQL INTERSECT 适合表达“两组查询结果的共同记录”。写 SQL 时先固定比较粒度,再确认列结构和 DISTINCT/ALL,最后区分整体排序与括号内的单侧限制。这样既能得到稳定的去重结果,也能避免把 UNION、EXCEPT 和 INTERSECT 的业务含义混在一起。
-
501 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
数据库 · MySQL | 46分钟前 | InnoDB · 故障排查 · MySQL教程 · mysql innodb mysqldump 二进制日志 物理备份 single-transaction 一致性备份270 收藏
-
数据库 · MySQL | 47分钟前 | 连接池 · 故障排查 · MySQL教程 · mysql 连接池 wait_timeout database/sql SetConnMaxIdleTime SetConnMaxLifetime 空闲连接 PingContext350 收藏
-
数据库 · MySQL | 49分钟前 | MySQL · 数据库 · csv · 数据导入 · CSV导入 MySQL LOAD DATA LOAD DATA LOCAL INFILE MySQL批量导入307 收藏
-
141 收藏
-
146 收藏
-
361 收藏
-
467 收藏
-
415 收藏
-
437 收藏
-
413 收藏
-
437 收藏
-
132 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习