不能。因为null = null返回unknown而非true,而join只保留on条件为true的行;需用is not distinct from、coalesce或显式or分支实现null安全比较。

ON条件里写 = 为什么两边都是NULL也不连上?
因为NULL = NULL返回的是UNKNOWN,不是TRUE;而JOIN只保留ON表达式求值为TRUE的行。UNKNOWN和FALSE一样,都被当作“不匹配”处理。这不是数据库bug,是SQL三值逻辑的强制行为。
常见错误现象:
-
INNER JOIN结果漏掉大量本该关联的记录(比如用户表和订单表都用ref_id关联,但双方ref_id都是NULL,却没连上) -
LEFT JOIN后右表字段全为NULL,你以为是没数据,其实是匹配逻辑根本没触发
PostgreSQL / MySQL 8.0.16+ 怎么用 IS NOT DISTINCT FROM?
这是SQL标准里专为NULL安全比较设计的操作符,语义是“值相等或两者同为NULL”。它比手写OR更简洁、更易读,且部分数据库能更好下推索引。
实操建议:
- PostgreSQL直接写:
ON a.id IS NOT DISTINCT FROM b.id - MySQL 8.0.16+支持,但某些版本在
JOIN中可能触发优化限制,建议先在EXPLAIN里确认执行计划 - 多个字段要逐个写:
ON a.id IS NOT DISTINCT FROM b.id AND a.name IS NOT DISTINCT FROM b.name,不能只在最后加一个OR兜底
兼容所有数据库的写法:手写 OR 分支
当目标库不支持IS NOT DISTINCT FROM(如SQL Server旧版、Oracle),必须显式展开每个字段的NULL判断逻辑。
关键点:
- 每个参与JOIN的字段都要独立处理:
ON (a.id = b.id OR (a.id IS NULL AND b.id IS NULL)) AND (a.code = b.code OR (a.code IS NULL AND b.code IS NULL)) - 别偷懒写成
ON a.id = b.id OR (a.id IS NULL AND b.id IS NULL AND a.code = b.code)——这会破坏短路逻辑,且语义错误 - 这种写法通常无法走索引,大数据量时性能明显下降,务必配合
WHERE范围过滤或分块执行
COALESCE 替换NULL的坑在哪?
用COALESCE(a.id, -1) = COALESCE(b.id, -1)看似简单,但容易埋雷。
必须检查:
- 兜底值
-1是否真的在业务中永不出现?哪怕某张表主键从1开始,也要确认外键字段、历史迁移数据、ETL中间态有没有意外写入 -
COALESCE会导致索引失效——如果a.id上有索引,COALESCE(a.id, -1)基本无法利用 - 类型要严格一致:
COALESCE(a.name, 'N/A')没问题,但COALESCE(a.id, 'N/A')在PostgreSQL里直接报错
真正麻烦的不是写法本身,而是把NULL当“值”来处理后,和原始业务语义脱节——比如两个NULL代表不同含义(“未填写” vs “不适用”),强行等同可能掩盖数据质量问题。











