left join 后 where right_table.col is null 能筛出左表独有数据,是因为左表全保留、右表无匹配时字段为null,where在此阶段显式选出空匹配行;on中写is null无效,且须用is null而非=null,建议建索引或改用not exists。

LEFT JOIN 后 WHERE col IS NULL 为什么能筛出左表独有数据
因为 LEFT JOIN 会保留左表所有行,右表无匹配时对应字段全为 NULL;用 WHERE right_table.id IS NULL 就能精准挑出那些“左表有、右表没”的记录。本质是利用了外连接的补空逻辑,不是靠过滤条件“排除”,而是“显式选出空匹配行”。
必须写成 WHERE right_table.col IS NULL,不能写 LEFT JOIN ... ON ... AND right_table.col IS NULL
把 IS NULL 条件放在 ON 子句里,会导致右表仍参与连接计算(只是匹配不到),最终结果中这些行的右表字段仍是 NULL,但左表行不会被过滤——等于白写。正确做法只在 WHERE 阶段筛。
-
ON t1.id = t2.id AND t2.status IS NULL→ 错:t2.status 本就可能为空,这会让连接条件变弱,甚至引入意外匹配 -
WHERE t2.id IS NULL→ 对:明确只取右表完全没匹配上的左表行
注意 NULL 安全比较和索引使用
IS NULL 是安全的,但如果你误写成 = NULL,结果永远是 UNKNOWN,查不出任何数据。另外,确保右表用于判断是否存在的字段(如 t2.id)上有索引,否则 WHERE t2.id IS NULL 可能触发全表扫描——尤其当右表很大时,性能会断崖下跌。
- 错误写法:
WHERE t2.id = NULL(永远不成立) - 正确写法:
WHERE t2.id IS NULL - 建议在右表的关联字段上建索引,例如
CREATE INDEX idx_t2_id ON t2(id);
替代方案:NOT EXISTS 通常更直观且易优化
虽然 LEFT JOIN ... WHERE IS NULL 能用,但语义上不如 NOT EXISTS 直接表达“不存在”。多数数据库(PostgreSQL、SQL Server、Oracle)对 NOT EXISTS 的子查询有更好优化,特别是右表有合适索引时。
SELECT t1.* FROM table1 t1 WHERE NOT EXISTS ( SELECT 1 FROM table2 t2 WHERE t2.ref_id = t1.id );
如果右表关联字段允许 NULL,NOT EXISTS 不会受干扰;而 LEFT JOIN 方式若右表该字段本身含 NULL 值,还得多加一层非空判断,容易漏。
实际写的时候,别只盯着语法能不能跑通,得看右表那列有没有 NULL、索引建没建、执行计划里是不是真走了索引——这些地方一松懈,查十万行就卡住。










