登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  数据库 >  MySQL

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,不会让最终结果重复。

MySQL INTERSECT 将 current_members 与 paid_users 两个查询块合并为共同用户结果的结构说明图
图1:INTERSECT 交集说明图,查看两个查询块与共同记录之间的静态关系;这不是运行截图。

让两侧查询具备兼容的列结构

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,复杂表达式最好用括号把业务意图写清楚。

MySQL INTERSECT 的列结构、DISTINCT、ALL、括号查询块和整体 ORDER BY 关系说明图
图2:集合运算语义边界图,查看列结构、重复策略与排序范围;这不是性能截图。

发布前用四项清单复查 SQL

  1. 结果意图:需求是共同记录、并集还是左侧差集?共同记录才使用 INTERSECT。
  2. 比较粒度:两侧选择的列是否都是同一业务粒度?多选一列可能让“按用户去重”变成“按用户和区域比较”。
  3. 重复策略:没有明确的重复计数需求时保留默认 DISTINCT;只有需要保留重复行时才使用 ALL。
  4. 作用范围:整体 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 的业务含义混在一起。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>