MySQL不支持INTERSECT,需用INNER JOIN实现交集:ON条件必须覆盖所有比较字段,且需显式处理NULL(如t1.col = t2.col OR (t1.col IS NULL AND t2.col IS NULL)),并建立对应联合索引以保障性能。

MySQL 里没有 INTERSECT,但用 INNER JOIN 能准确、高效地实现两表交集——前提是明确“交集”的语义是「所有指定字段值完全一致的行」。
为什么不能直接用 INTERSECT?
MySQL 直到 8.0.31 版本仍不支持标准 SQL 的 INTERSECT(仅 Oracle、SQL Server、PostgreSQL 等支持)。强行写会报错:ERROR 1064 (42000): You have an error in your SQL syntax。别被其他数据库文档误导,MySQL 就是没这个语法。
- 试图用
UNION或UNION ALL模拟交集,逻辑上不可靠(它做的是并集) -
NOT IN+ 子查询是差集思路,不是交集,且对NULL敏感、性能差 - 真正等价于交集的行为:只保留两表中「所有参与比较的列都严格相等」的行
INNER JOIN 实现交集的正确写法
关键不是「有没有 JOIN」,而是「ON 条件是否覆盖全部要对比的字段」。以知识库中的 t1 和 t2 为例,若要求 id、name、age 全部相同才算交集:
SELECT t1.* FROM t1 INNER JOIN t2 ON t1.id = t2.id AND t1.name = t2.name AND t1.age = t2.age;
- 必须把所有要参与交集判断的字段都写进
ON,不能漏掉任何一个 - 用
INNER JOIN而非LEFT JOIN,否则会带出不匹配的 NULL 行 - 如果只按
id关联,那结果其实是「主键交集」,不是全字段交集——语义已偏移
容易被忽略的 NULL 陷阱
INNER JOIN 的 = 判断在遇到 NULL 时永远返回 FALSE(SQL 中 NULL = NULL 是未知,不是真)。所以以下两行在 t1 和 t2 中即使看起来一样,也不会被 INNER JOIN 匹配出来:
t1: (5, '阿强', NULL) t2: (5, '阿强', NULL)
- 这不是 bug,是 SQL 标准行为。想让 NULL 参与交集,得显式改写条件:
(t1.age = t2.age OR (t1.age IS NULL AND t2.age IS NULL)) - 字段越多,NULL 处理越繁琐;此时可考虑用
COALESCE(t1.age, -999) = COALESCE(t2.age, -999),但需确保替换值不真实存在 - 生产环境若字段允许 NULL,务必先确认业务是否把 NULL 视为“相等”
性能与索引建议
INNER JOIN 交集查询能否走索引,取决于 ON 中字段的组合索引是否存在:
- 单字段索引(如仅
id有索引)对多字段ON条件帮助有限 - 应为参与交集判断的所有字段建联合索引,顺序按
ON中出现顺序,例如:CREATE INDEX idx_t2_id_name_age ON t2(id, name, age); - 如果表很大且只查交集,比
WHERE ... IN (SELECT ...)快一个数量级——后者可能触发全表扫描
交集的本质是「精确匹配」,不是模糊查找。写 INNER JOIN 时,每一行 ON 条件都得像校验身份证号一样严丝合缝,少一个等号、漏一个 NULL 处理,结果就不是你要的交集。










