早上刚开完站会,测试小姐姐又甩过来一条 SQL:
SELECt u.name, o.order_noFROM user AS uLEFT JOIN `order` AS o ON u.id = o.user_idWHERe o.status = 1;“不是说 LEFT JOIN 要保留所有用户吗?怎么结果少了一半?”
我扫了一眼,心里默默叹了口气:又是老问题——WHERe 里写了右表字段,把 LEFT JOIN 活生生写成了 INNER JOIN。
坑是怎么来的
LEFT JOIN 的语义是:左表全留,右表能匹配上就带过来,匹配不上就补 NULL。
但 WHERe 子句在 JOIN 之后执行。一旦你在 WHERe 里对右表字段做判断,比如:
WHERe o.status = 1数据库必须先把 o.status 为 NULL 的行扔掉(NULL = 1 不成立),于是那些“没订单”的用户就被一并踢出去。
LEFT JOIN 的初心瞬间破功。
一句话记住规则
右表字段进 WHERe,LEFT 变 INNER;想留 NULL,条件写 ON。
改法:把条件挪到 ON 里
SELECt u.name, o.order_noFROM user AS uLEFT JOIN `order` AS o ON u.id = o.user_id AND o.status = 1; -- 挪到这里现在结果里:
- 有订单且 status=1 → 订单号正常显示
- 没订单或 status≠1 → 订单号显示 NULL,用户依旧存在
这才是 LEFT JOIN 该有的样子。
小结
- 检查所有 LEFT JOIN,看 WHERe 里有没有右表字段。
- 有就搬到 ON 里,除非你真的只想保留“匹配成功”的行——那不如直接用 INNER JOIN,语义更清晰。
写完这条提示,我顺手贴在团队 Wiki 最显眼的位置:
“LEFT JOIN 里写右表条件,先问问自己:我到底想留 NULL 吗?”
