当前位置:首页 > 文章列表 > 数据库 > MySQL > MySQL INTERSECT 怎样找出两组查询的共同记录

MySQL INTERSECT 怎样找出两组查询的共同记录

来源:17golang原创 2026-10-26 20:20:44 0浏览 收藏

如果需求是“只保留两组查询都查到的记录”,MySQL 可以直接使用 INTERSECT:左侧查询和右侧查询返回的相同行会留下,默认按 DISTINCT 去重;只有明确写成 INTERSECT ALL 时,重复次数才会参与结果。先记住一个边界:它比较的是两边 SELECT 出来的完整行,不会自动按主键或列名猜测匹配关系。

本文以 MySQL 8.4 手册语义说明,MySQL 8.0 需要至少 8.0.31 才能使用这组集合运算。官方地址:https://dev.mysql.com/doc/refman/8.4/en/intersect.html。下面的 CTE 和查询都是原创示例,用来推导结果口径,不把示例输出当作本机执行截图。

先还原共同记录的查询现场

先假设我们要找“报名名单”和“签到名单”中同时出现的用户。第一眼容易把 INTERSECT 当成“按 user_id 关联”,但它真正看到的是每条查询输出的整行。因此,先把两侧都投影成同一个业务对象,再观察结果。

-- 两侧都只返回用户编号,比较单位就是 user_id
WITH signup AS (
    SELECT 101 AS user_id UNION ALL
    SELECT 102 UNION ALL
    SELECT 103
), checked_in AS (
    SELECT 102 AS user_id UNION ALL
    SELECT 103 UNION ALL
    SELECT 104
)
SELECT user_id FROM signup
INTERSECT
SELECT user_id FROM checked_in
ORDER BY user_id; -- 最终展示顺序由结果级排序决定

按集合语义,交集是 102 和 103。101 只在报名侧出现,104 只在签到侧出现,都不会进入交集。这里的关键线索是:两侧返回一列、列的业务含义一致,所以“共同记录”就是共同的用户编号。

报名查询和签到查询投影到共同用户编号后形成交集的静态结构图
图1:静态结构说明图,查看两侧查询范围、共同列投影和 INTERSECT 结果之间的关系。

从列投影定位为什么结果不全

如果把 status、source 等附加字段也选出来,比较单位就从“用户编号”变成了完整元组。例如左侧返回 (102, '报名'),右侧返回 (102, '签到'),即使编号相同,整行仍然不同,交集可能为空。

-- 只想按 user_id 求交集,两边都不要混入展示字段
SELECT user_id
FROM signup_record
WHERE campaign_id = ? -- 由应用参数绑定活动范围
INTERSECT
SELECT user_id
FROM checkin_record
WHERE campaign_id = ? -- 右侧也必须限定同一业务范围
ORDER BY user_id;

两侧必须有相同数量的列,对应位置要有可比较的类型和相同的业务含义。不要用 SELECT * 隐含决定比较契约:表结构增加字段后,交集语义也可能跟着变化。若业务对象是“用户 + 活动”,就让两侧都返回 user_id, campaign_id,不要只返回用户编号而把活动范围留在想象中。

INTERSECT 按列位置比较完整元组而不是自动按主键匹配的静态结构图
图2:静态结构说明图,比较列的位置和业务含义共同决定一行是否属于交集。

用 DISTINCT 与 ALL 验证重复记录口径

接下来排查最容易误读的重复情况。默认的 INTERSECT 等价于 INTERSECT DISTINCT,一条共同元组最多保留一次;INTERSECT ALL 则按两侧出现次数的较小值保留。

-- 默认去重:共同的 102 只保留一条
WITH left_rows AS (
    SELECT 102 AS user_id UNION ALL SELECT 102 UNION ALL SELECT 103
), right_rows AS (
    SELECT 102 AS user_id UNION ALL SELECT 104
)
SELECT user_id FROM left_rows
INTERSECT DISTINCT
SELECT user_id FROM right_rows;

-- 保留重复次数:102 在两侧各出现一次,所以仍只保留一条
WITH left_rows AS (
    SELECT 102 AS user_id UNION ALL SELECT 102 UNION ALL SELECT 103
), right_rows AS (
    SELECT 102 AS user_id UNION ALL SELECT 104
)
SELECT user_id FROM left_rows
INTERSECT ALL
SELECT user_id FROM right_rows;

若右侧也有两个 102,INTERSECT ALL 才会让结果保留两条;可以把每个元组的结果次数理解为 min(左侧次数, 右侧次数)。需要唯一名单时省略修饰词或写 DISTINCT;需要对账、配额或多重集合次数时才选择 ALL,不要把 ALL 当成“右侧出现过就把左侧重复行全部留下”。

补上查询范围、括号和最终排序

共同记录只对两组输入负责,不会替应用自动补上租户、活动或时间范围。左右查询应分别写清授权范围,并通过驱动参数绑定值。若还混用 UNION 或 EXCEPT,要用括号表达业务分组,因为 MySQL 会优先计算 INTERSECT。

-- 先限定两个来源,再明确交集参与 UNION 的哪一侧
(SELECT user_id
 FROM signup_record
 WHERE tenant_id = ? AND campaign_id = ?)
INTERSECT
(SELECT user_id
 FROM checkin_record
 WHERE tenant_id = ? AND campaign_id = ?)
UNION
SELECT user_id
FROM manual_allowlist
WHERE tenant_id = ?
ORDER BY user_id; -- 结果级排序不要依赖来源表顺序

最终 ORDER BY 应放在整个集合表达式上。若要先对某一侧单独使用 LIMIT 或排序,应把那一侧包在括号中,明确“先截取候选,再参与交集”的意图。空结果并不一定是语法问题,先检查两边的范围条件、列投影和真实数据是否确实没有共同元组。

复查结果并记录可解释的口径

到这里可以按五项复查:服务器版本支持 INTERSECT;左右方向和范围正确;列数、位置、类型和业务含义一致;重复结果选择了 DISTINCT 或 ALL;最终结果有稳定排序。对定期报表或对账任务,还应记录查询时间、过滤条件和集合修饰词,因为源表变化后,同一 SQL 可能得到不同结果。

最短结论是:先把两侧查询投影成同一个业务对象,再决定唯一交集还是次数交集,最后用范围条件、括号和结果排序固定口径。

常见问题

为什么两个查询都有同一个 ID,INTERSECT 还是没有结果?

检查两侧是否还选了状态、来源等其他列。INTERSECT 比较完整行,同一个 ID 配上不同字段并不相等;如果业务只按 ID 判断,就让两侧都只返回 ID。

INTERSECT 和 INNER JOIN 怎样选择?

只需要两个查询结果的共同元组时,INTERSECT 更直接;需要同时读取一侧的明细列、按关联条件扩展结果时,再考虑 JOIN。两者的列投影和重复语义不能混为一谈。

能不能依赖结果自然顺序?

不能。集合运算的输出顺序不应当作为业务规则,展示或导出前请在整个结果上明确写 ORDER BY。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
MySQL EXCEPT 怎样排除另一查询的结果行MySQL EXCEPT 怎样排除另一查询的结果行
上一篇
MySQL EXCEPT 怎样排除另一查询的结果行
MySQL TABLE 语句怎样直接读取整张表
下一篇
MySQL TABLE 语句怎样直接读取整张表
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • PubMedQA数据集详解:生物医学问答基准、功能与应用指南
    PubMedQA
    深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
    718次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    724次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    801次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    761次使用
  • MMBench详解:多模态大模型基准测试、功能特点与使用指南
    MMBench
    MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
    594次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议 和 隐私政策
返回登录
  • 重置密码