LEFT JOIN右表条件应写在ON而非WHERE,否则会丢失左表无匹配的记录;ON中加条件只影响关联逻辑,WHERE中过滤则等同INNER JOIN。

LEFT JOIN后右表条件该写在ON还是WHERE?
写在ON里才能保住左表全量,写在WHERE里就等同于INNER JOIN。这是最常踩的坑——你以为查的是“所有用户+他们的已完成订单”,结果没下单的用户全没了。
-
ON u.id = o.user_id AND o.status = 'completed':只影响匹配逻辑,没订单或订单非 completed 的用户仍保留,o.order_id为NULL -
WHERE o.status = 'completed':关联完再过滤,把o.status是NULL的行直接踢掉 - ORM 用户注意:
where()默认生成WHERE条件,得用on()或显式拼AND到关联条件里
如何安全判断右表是否匹配成功?
别用业务字段(比如 o.total_amount)做判空,它本身可能合法为 NULL。真正可靠的依据是连接字段或主键是否为 NULL。
- 检查是否有订单:
CASE WHEN o.order_id IS NOT NULL THEN '有' ELSE '无' END - 如果右表是复合主键,优先选最不可能为空的字段,比如
o.id或o.order_id,而不是o.discount_code - 聚合统计时:
COUNT(*)算左表总行数,COUNT(o.order_id)才算实际匹配的订单数
多表LEFT JOIN时ON条件怎么串才不丢数据?
每层 LEFT JOIN 都基于前一步结果扩展,不能跳过中间表直接拉远端字段。否则一旦中间结果出现 NULL,后续关联就失效。
- 正确写法:
LEFT JOIN orders o ON u.id = o.user_id→LEFT JOIN products p ON o.product_id = p.id - 错误写法:
LEFT JOIN products p ON u.preferred_product_id = p.id(绕过 orders 表,语义断裂) - 如果某层右表字段可能为
NULL(如o.product_id),下一层ON会自然失效,整行仍保留,但p.name也为NULL
NULL值怎么处理才不影响计算和展示?
直接参与运算或字符串拼接会传播 NULL,前端看到空白或后端报错。必须主动兜底,但兜底方式要匹配业务语义。
- 数值型字段用
COALESCE(o.amount, 0),避免NULL + 100得NULL - 文本型字段用
COALESCE(p.name, '未知商品'),比硬写IS NULL判断更简洁 - 慎用
WHERE o.created_at > '2024-01-01'——NULL > xxx永远是FALSE,会漏掉所有无订单用户;真要筛时间,得加OR o.created_at IS NULL,但通常已偏离原意
LEFT JOIN,只要某一个 WHERE 引用了最右边表的字段,整条链的左表完整性就可能崩掉。

















