LEFT JOIN + WHERE 右表主键 IS NULL 是查找左表有而右表无记录的可靠方式;必须用右表主键或NOT NULL字段判空,避免误用可空字段导致错判,且需为右表关联字段建索引以保障性能。
想找出左表有、右表没有的记录,不能只靠 LEFT JOIN 本身——它默认会把右表字段填成 NULL,但你得显式筛出来。关键在 WHERE 子句里加右表主键或非空字段的 IS NULL 判断,否则会漏掉或错判。
ON 条件只控制连接逻辑,不过滤结果;WHERE 才真正剔除行NULL」的字段(比如主键、带 NOT NULL 约束的列),用 IS NULL 才有意义NULL 的字段(如备注字段),可能把本该保留的记录也过滤掉假设 orders 表有 customer_id,customers 表主键是 id:
SELECT o.* FROM orders oLEFT JOIN customers c ON o.customer_id = c.idWHERE c.id IS NULL;
这里必须用 c.id IS NULL,而不是 o.customer_id IS NULL——后者查的是「订单本身就没填客户 ID」的记录,不是「客户 ID 存在但客户表里找不到」。
这些写法都会出问题:
IS NULL 放到 ON 子句里:LEFT JOIN customers c ON o.customer_id = c.id AND c.id IS NULL —— 这会让 LEFT JOIN 变成无效连接,结果等价于 CROSS JOIN 加过滤,极慢且语义错误WHERE c.name IS NULL —— 如果客户表里真有 name 为 NULL 的合法记录,就会被误删WHERE,只写 LEFT JOIN —— 结果包含所有左表记录,混着匹配成功和失败的行,没法区分这个查询实际执行时,数据库仍需扫描右表来确认是否匹配。如果右表很大,没索引会很慢:
JOIN 条件中的右表字段(如 customers.id)有索引WHERE ... IS NULL 场景下可能无法利用索引,建议用 EXPLAIN 看执行计划最易忽略的一点:很多人以为 LEFT JOIN 后右表字段为 NULL 就代表“不存在”,却没验证那个 NULL 是连接失败导致的,还是右表本身就存了 NULL。务必用主键或非空约束字段做判断。