← [ BACK_TO_NOTES ]

SQL JOIN 中 ON 与 WHERE 的过滤边界

解释 OUTER JOIN 中 ON 控制哪些右表行能够匹配,WHERE 控制联表后哪些结果行保留,以及条件放错位置为何会破坏 LEFT JOIN 语义。

#synthesis #growing #backend #sql #database

[!info] related notes

SQL JOIN 中 ON 与 WHERE 的过滤边界

范围

这篇只讨论 JOIN 场景里 ON 和 WHERE 的语义边界,尤其是 LEFT JOIN。

核心区别

ON
→ 哪些右表行有资格与左表匹配

WHERE
→ JOIN 完成后,哪些结果行还能保留

对 INNER JOIN,很多条件放在 ON 或 WHERE 最终可能得到相同结果;对 LEFT JOIN,二者经常不等价。

典型陷阱

需求:返回所有用户,以及每个人已发布文章的数量,包括 0 篇的用户。

条件放 WHERE

SELECT u.id, COUNT(a.id)
FROM users u
LEFT JOIN articles a
  ON a.user_id = u.id
WHERE a.status = 'published'
GROUP BY u.id;

没有 published Article 的用户会得到:

user | a.status = NULL

NULL = 'published' 不为 TRUE,所以 WHERE 把整行删除,LEFT JOIN 的“保留左表”效果被破坏。

条件放 ON

SELECT u.id, COUNT(a.id)
FROM users u
LEFT JOIN articles a
  ON a.user_id = u.id
 AND a.status = 'published'
GROUP BY u.id;

此时 status 只决定哪些 Article 能匹配;匹配不到时 User 仍保留,a.id = NULL,所以 COUNT(a.id) = 0。

判断规则

问自己两个问题:

  1. 这是“关系匹配条件”吗?——倾向放 ON。
  2. 这是“最终结果必须满足的条件”吗?——倾向放 WHERE。

如果要求保留 OUTER JOIN 的未匹配行,对右表的过滤尤其要谨慎。

不要机械化

这不是“右表条件永远放 ON”。如果业务就是要求最终只保留满足右表条件的结果,那么 WHERE 完全合理。关键是先明确是否还需要保留未匹配左表行。

与 HAVING 的边界

  • ON:控制 JOIN 匹配。
  • WHERE:过滤 JOIN 后、分组前的行。
  • HAVING:过滤 GROUP BY 后的组。

三者解决的是不同阶段的问题。

创建于 2026/9/14 更新于 2026/9/14
Digital Biome
Access

键盘导航

j / k / ↑ / ↓
选择对象
Enter / o
打开选择
/ 或 Ctrl+K
全站搜索
i / f / 1–4
筛选当前列表
g → h / l / p / t / a
首页 / 笔记 / 项目 / 工具 / About
r → 1–9
打开所选对象的关联
u
返回上一页
Esc
关闭浮层 / 取消命令;输入框内清空文本