SQL中JOIN的ON条件不匹配NULL值,因NULL比较结果为UNKNOWN而非TRUE;INNER JOIN会跳过含NULL的行,外连接仅保留但不匹配NULL;需用OR、COALESCE或IS NOT DISTINCT FROM显式处理NULL相等。

SQL 中 JOIN 的 ON 条件对 NULL 值**不进行匹配**——这是核心规则。因为 NULL 表示“未知”,而任何与 NULL 的等值比较(如 col1 = col2)结果都不是 TRUE,而是 UNKNOWN;而 JOIN 只保留条件评估为 TRUE 的行,UNKNOWN 被当作不匹配处理。
INNER JOIN 遇到 NULL 就跳过
如果连接列中任一值为 NULL,该行不会出现在 INNER JOIN 结果中。
- 例如:
t1.id = 1, t1.code = NULL与t2.id = 1, t2.code = NULL—— 尽管都为 NULL,但NULL = NULL返回 UNKNOWN,不满足 JOIN 条件,因此无匹配。 - 即使两表都有相同含义的空值(比如“未填写”),默认也不会连上。
外连接能保留 NULL 行,但不自动匹配 NULL
LEFT/RIGHT/FULL OUTER JOIN 的作用是**保留某侧或两侧的所有行**,包括那些本该因无匹配而丢失的 NULL 行,但它本身并不改变 NULL 的比较逻辑。
-
LEFT JOIN ... ON t1.a = t2.b:t1 中a IS NULL的行仍会出现在结果里,但对应 t2 列全为 NULL(表示未找到匹配),并非因为 NULL 和 NULL 匹配成功。 - 结果中会出现两类 NULL:原始数据里的 NULL(真实缺失值),和外连接产生的 NULL(匹配失败标记),二者语义不同,容易混淆。
想让 NULL 和 NULL 视为相等?得手动写逻辑
数据库不会默认把两个 NULL 当作相同值来连,必须显式声明这种意图。常用方法有:
-
用 OR 显式包含 NULL 对 NULL 的情况:
ON (t1.col = t2.col) OR (t1.col IS NULL AND t2.col IS NULL) -
用 COALESCE 统一替换 NULL(注意避免与真实值冲突):
ON COALESCE(t1.col, '>') = COALESCE(t2.col, '>') -
在支持的数据库中使用 IS NOT DISTINCT FROM(PostgreSQL、SQL Server 2022+):
ON t1.col IS NOT DISTINCT FROM t2.col—— 这是语义上最准确的 NULL 安全比较。
为什么不能依赖 WHERE 处理 JOIN 后的 NULL?
有人试图用 WHERE t1.col = t2.col OR (t1.col IS NULL AND t2.col IS NULL) 替代 ON 条件,这是错误的。WHERE 是在 JOIN 完成后过滤结果,此时 INNER JOIN 已经丢弃了所有含 NULL 的潜在匹配行,WHERE 再怎么写也找不回来。逻辑必须放在 ON 中。










