SQL JOIN 中 NULL 值是如何匹配的?

11次阅读

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

SQL JOIN 中 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 = NULLt2.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 FROMpostgresql、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 中。

text=ZqhQzanResources