不能。SQL标准下NULL = NULL返回UNKNOWN,而JOIN只保留ON条件为TRUE的行,故不匹配;需用IS NOT DISTINCT FROM、COALESCE或显式OR分支实现NULL安全比较。

为什么 NULL = NULL 在标准 SQL 中永远为 FALSE
因为 SQL 的三值逻辑规定:任何与 NULL 的比较(包括 =、!=、)都返回 UNKNOWN,而 JOIN 的 ON 条件只接受 TRUE 行。所以即使两列都是 NULL,a.col = b.col 也不会匹配。
用 IS NOT DISTINCT FROM 实现 NULL 安全等值 JOIN
这是最干净、语义最明确的方案,PostgreSQL、SQL Server(2022+)、Trino、DuckDB 等已支持;MySQL 和 SQLite 尚未原生支持(需绕行)。
-
ON a.key IS NOT DISTINCT FROM b.key—— 同时处理非NULL相等和NULL 与 NULL两种情况 - 比
(a.key = b.key) OR (a.key IS NULL AND b.key IS NULL)更简洁、可读性更高、也更易被优化器识别 - 在 PostgreSQL 中,该表达式还能利用 B-tree 索引(只要字段支持排序),性能接近普通等值 JOIN
兼容旧版数据库的等效写法(如 MySQL、SQLite、老版本 SQL Server)
必须显式拆解逻辑,但要注意括号优先级和 NULL 传播风险。
- 正确写法:
ON (a.key = b.key) OR (a.key IS NULL AND b.key IS NULL) - 错误写法:
ON a.key = b.key OR a.key IS NULL AND b.key IS NULL—— 因为AND优先级高于OR,实际等价于(a.key = b.key OR a.key IS NULL) AND b.key IS NULL,逻辑完全错乱 - 如果涉及多个字段联合判断(如
(a.x, a.y)与(b.x, b.y)),需分别展开:ON (a.x = b.x OR (a.x IS NULL AND b.x IS NULL)) AND (a.y = b.y OR (a.y IS NULL AND b.y IS NULL))
避免用 COALESCE 替换 NULL 做 JOIN 的陷阱
常见但危险的做法:ON COALESCE(a.key, '~~MISSING~~') = COALESCE(b.key, '~~MISSING~~')
- 若原始字段本身可能含
'~~MISSING~~'(或任意你选的哨兵值),就会误匹配 - 若字段是数值型,
COALESCE(a.num, -999999)可能与真实数据冲突 - 强制类型转换可能引发隐式转换开销,且索引通常失效(尤其当函数作用于列上)
- 仅当业务能 100% 保证哨兵值绝对不出现时才可考虑,否则属于埋雷
真正安全的 NULL 意识 JOIN,核心就两条:优先用 IS NOT DISTINCT FROM;不能用时,老老实实写带括号的 OR 条件。别图省事去“伪造”非 NULL 值——那只是把问题从逻辑层转移到数据层。










