left join 的“保左表”特性在 where 中过滤右表字段时失效,因 where 在 on 之后执行,null 值被过滤;正确做法是将右表过滤条件移入对应 on 子句。

LEFT JOIN 的“保左表”特性在 WHERE 里写右表字段时会彻底失效——不是数据库出错,是 SQL 执行顺序决定的必然结果。
WHERE 里写了 t2.status = 'active' 就等于变 INNER JOIN
LEFT JOIN 先执行 ON,生成中间结果(左表全保留,右表不匹配则填 NULL),WHERE 是最后一步,对这个中间结果做全局过滤。而 NULL = 'active' 判定为 UNKNOWN,整行被直接剔除。
- 错误写法:
LEFT JOIN orders t2 ON t1.id = t2.user_id WHERE t2.status = 'active'→ 没订单的用户全消失 - 正确写法:
LEFT JOIN orders t2 ON t1.id = t2.user_id AND t2.status = 'active'→ 用户全在,没匹配上的t2.order_id是NULL - 调试技巧:先
SELECT *看右表字段是否批量为NULL;再查EXPLAIN输出里rows是否远小于左表总行数
多层 LEFT JOIN 时,最外层 WHERE 会把整条链“一锅端”
比如 users → orders → order_items,若在最外层写 WHERE oi.category = 'electronics',那所有没买电子产品的用户都会丢,哪怕他们有订单。
一款AI工具,主要用于Codex 通用编排:利用 `update_plan` 与后台 PTY 终端并行运行 `codex exec` 工作进程,适合需要提升相关任务效率的用户。
- 危险写法:
LEFT JOIN order_items oi ON o.id = oi.order_id WHERE oi.category = 'electronics' - 安全写法:
LEFT JOIN order_items oi ON o.id = oi.order_id AND oi.category = 'electronics' - 关键原则:每层
LEFT JOIN中,只要条件涉及该层右表字段,就必须塞进对应ON,不能指望上层WHERE补救
ON 和 WHERE 不是位置不同,是语义完全不同
ON 决定“哪些右表行能连上来”,WHERE 决定“连完之后留哪些整行”。混用不仅逻辑错乱,跨数据库还可能行为不一致(比如老版 MySQL 或 Presto)。
-
ON应只放关联逻辑:如t1.id = t2.ref_id、类型安全转换(CAST(t2.user_id AS UNSIGNED)) -
WHERE只放真正需要全局筛的字段:如t1.status = 'active'、时间范围、权限控制字段 - 别在
ON里用函数(如UPPER()),索引大概率失效;也别在WHERE里依赖右表字段判空来统计左表——COUNT(*)和COUNT(t2.id)含义完全不同
最容易被忽略的是:当右表字段本身允许 NULL(比如 status 字段业务上可为空),用 WHERE t2.status IS NULL 查“未匹配”会混入脏数据;必须用 t2.id IS NULL 或 t2.user_id IS NULL 这类外键字段才可靠。










