SQL语句中LEFT JOIN的ON和WHERE有什么区别

苏见山
苏见山
发布时间:2026-10-15| 3人浏览过
原创

在使用 SQL 的 LEFT JOIN 关联多表查询时,很多开发者发现将筛选条件写在 ON 子句中和 WHERE 子句中会产生截然不同的结果集。ON 条件用于界定连接时的匹配逻辑,无论是否匹配成功,左表记录都会保留;而 WHERE 条件是在中间结果生成后进行的二次过滤,会直接剔除不满足条件的行,导致 Left Join 失去保护左表数据的特性。

结果与目标:理解两种过滤时机

编写 SQL 时若希望通过关联条件筛选右表的记录而不影响左表展示,必须准确掌握 ON 与 WHERE 的执行时序。核心结论如下:

  • ON 条件:决定左右表如何“拼接”。它控制右表中哪些列进入最终结果,但不删除左表的行。
  • WHERE 条件:决定最终“保留”哪些记录。它在拼接完成后过滤整个临时表,不满足的行将被丢弃,从而破坏 Left Join 的预期效果。

第1步:查看 ON 条件下的实际表现

我们首先通过一个业务场景演示 ON 条件的作用。假设有两个表:chat_user(用户表)和 chat_communication(消息表)。我们需要列出所有用户及其发送的消息。

当我们在 ON 中加入额外的限制条件时,例如只查找特定用户或消息发送者,左表的所有用户依然会全部显示,只是右表对应不上的部分字段变为 NULL。这证明了 ON 不会过滤左表行数。

示例 A:基础 Left Join
以下查询未加额外限制,展示了所有用户的聊天记录:

SELECT u.id,u.nickname,c.content FROM chat_user u
LEFT JOIN chat_communication c
on u.id=c.toid order by c.id;

示例 B:在 ON 中添加左侧过滤条件 (u.nickname="大金")
尽管加了名字判断,非大金的用户依然在列表中,只不过聊天内容显示为 NULL:

SELECT u.id,u.nickname,c.content FROM chat_user u
LEFT JOIN chat_communication c
on u.id=c.toid and u.nickname="大金" order by c.id;

示例 C:在 ON 中添加右侧过滤条件 (c.fromname="雨薇")
同理,这里限制了仅提取雨薇发送的消息,但其他用户仍在结果集中,未找到雨薇记录的则显示 NULL:

SELECT u.id,u.nickname,c.content,c.fromname FROM chat_user u
LEFT JOIN chat_communication c
on u.id=c.toid and c.fromname="雨薇" order by c.id;

第2步:对比 WHERE 条件的过滤效果

为了更直观地展示两者的差异,我们可以利用两张测试表进行对照实验。

  1. 创建测试数据:
    - test1 (id: 1-3, size: 10, 20, 30)
    - test2 (size: 10 AAA, 20 BBB, 20 CCC)
CREATE TABLE test1(id int,size int); 
INSERT INTO test1 VALUES (1,10),(2,20),(3,30); 
CREATE TABLE test2(size int,nikname varchar(10));
INSERT INTO test2 VALUES (10,"AAA"),(20,"BBB"),(20,"CCC"); 

接下来,分别使用 WHERE 和 ON 来筛选 test2 表中 nikname = 'AAA' 的记录。

情况一:使用 WHERE 过滤(错误做法)
先在 ON 进行大小匹配,生成中间表后,再用 WHERE 过滤名称。因为 Left Join 生成的临时表中只有 id=1 的记录有 "AAA",其余行的 nikname 都是 NULL 或 BBB/CCC,所以最终只剩下 1 条记录:

SELECT * FROM test1
LEFT JOIN test2 ON (test1.size = test2.size)
WHERE test2.nikname = "AAA";
-- 结果:只返回了 1 行数据,失去了 Left Join 的特性

情况二:使用 ON 过滤(推荐做法)
直接将名称条件合并到 ON 子句中作为连接规则。由于 ON 条件不为真也会返回左表中的记录,因此即使没有找到 "AAA",id=2 和 id=3 的数据依然会完整保留:

select * FROM test1 left join test2 
on (test1.size = test2.size and test2.nikname="AAA");
-- 结果:保留了 test1 的全部 3 行数据

第3步:底层原理分析

理解这一机制的关键在于 SQL 引擎处理连接的过程:

  • 临时表生成阶段 (ON):数据库根据 LEFT JOIN 的规则结合 ON 后的条件构建一张临时的中间表。如果左表某行在右表中找不到符合 ON 条件的匹配项,该行不会被丢弃,而是用 NULL 填充右表部分的空位。
  • 过滤阶段 (WHERE):在这张已经确定的临时表上应用 WHERE 子句。此时不再存在“必须有左表记录”的特殊约束,任何不满足条件的行(包括那些因未匹配而变成 NULL 的行)都会被彻底删除。

这也解释了为什么 INNER JOIN 放在 ON 或 WHERE 里结果通常是一样的——因为它本来就会在任何一个条件不满足时都删除记录。而对于 LEFT JOIN、RIGHT JOIN 或 FULL JOIN,区分条件放置的位置至关重要。

完成判断

如果你在写关联查询时,希望基于右表的某些属性进行过滤,同时保证左表的主记录(如用户、订单等)始终可见(哪怕关联数据为空),请务必将这些过滤条件写入 ON 子句中。如果你发现原本应该存在的左表主键记录凭空消失,请检查是否误将它们放在了 WHERE 之后。

总结

以上就是 SQL LEFT JOIN 的 ON 条件与 WHERE 条件区别的核心内容。掌握连接时的筛选时机是优化复杂查询的基础。更多关于 SQL 进阶技巧与语法细节的资料请关注本站其它相关文章!

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。