SQL 查询条件放在LEFT OUTER JOIN 的ON语句后与放在WHERE中的区别

本文解析了SQL左连接中ON与WHERE条件的区别,重点介绍了条件放置位置对查询结果的影响,并通过实例说明如何正确使用这些条件以获得预期结果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这两种条件放置的位置不同很容易让人造成混淆,以致经常查询出莫名其妙的结果出来,特别是副本的条件与主表不匹配时,下面以A,B表为例简单说下我的理解。

首先要明白的是:

跟在ON 后面的条件是对参与左联接的数据进行筛选,即在左联接之前起作用。

跟在WHERE后的条件是对左联接得到的结果集进行筛选,即在左联接之后起作用。

 

我直接把我的结论发出来,建议朋友们自行测试一下,下面是结论:

1) 如果条件是由主表和副表之间的字段构成,那么放在ON后与放在WHERE子条件中所得到的结果是一样,即这种条件可以随便放,甚至在SQL中建视图时,会自动优化放到ON条件后。

如下:

select * from A LEFT OUTER JOIN B ON A.Id=B.UserId AND A.Name=B.UserName

select * from A LEFT OUTER JOIN B ON A.Id=B.UserId WHERE A.Name=B.UserName

上面两个语句的结果是一样的,如果用这条语句去建视图,SQL管理器会自动优化成第一句的写法,大家可以亲自试验下。

 

2)如果条件是由进行左联接的两个表中的一个表的字段构成,则结果会很不一样。

1:select * from A LEFT OUTER JOIN B ON A.Id=B.UserId AND B.IsDel=0 (IsDel意思为记录是否删除,0为否,1为是。)

2:select * from A LEFT OUTER JOIN B ON A.Id=B.UserId WHERE B.IsDel=0

以上两句语句使用时要非常注意,这两种写法得到的数据是不一样的。

第一句的意思是:在进行左联接前,先从表B中筛选出没有标记为删除的数据后得到的结果再与A表进行左联接。

而第二句的意思是:在A,B表进行左联接后的,再对得到的结果进行“B.IsDel=0”条件过滤。

如果A表中有2条数据,在B表中都能匹配上,那么得到的结果是一样的,但是,假设A中只有一条记录在B中能匹配上,那么两条语句得到的结果就不一样了。

因为两表左联接后得到的结果集中的对应B.IsDel的列(假设生命为B_IsDel)的值其实是NULL值,那么再进行“B_IsDel=0”,这条记录就会被过滤掉了,

即最终的结果是第一条语句有两条数据,第二条语句只有一条。

 

此外,还有下面这种更离奇的情况,假设我们的需求是对A,B两表进行左联接,同时希望过滤掉A表中已经被删除了的数据和B表中已经被删除了的数据。可能会有如下两种写法:

3:select * from A LEFT OUTER JOIN B ON A.Id=B.UserId AND A.IsDel=0 AND B.IsDel=0 (IsDel意思为记录是否删除,0为否,1为是。)

4:select * from A LEFT OUTER JOIN B ON A.Id=B.UserId WHERE A.IsDel=0 AND B.IsDel=0 

 

语句4能得到想要的结果。

语句3,这种写法很少见,执行后,大家会发现语句3的结果中包含了A表中A.IsDel=1的记录,这是为什么呢?

原因很简单,因为它是左联接,下面解释一下:

我们知道左联接的逻辑是A表或者说主表中的数据都会出现在最终的结果集中,那么“A.IsDel=0”这个条件在语句3左联接的过程起到了什么作用呢?

  其作用是系统在进行左联接时,先在A表中用"A.IsDel=0"条件过滤数据(假设过滤掉了R1这条数据),用过滤后的结果再与B表进行左联接,

  但最后整个语句返回的结果集中极会包含R1这条数据,只不过这条记录对应的B表中的字段全部为NULL值。请大家自行测试理解。

 

此时,如果想要达到我们的目的,必需在WHERE子句中增加A.IsDel=0条件,即:

select * from A LEFT OUTER JOIN B ON A.Id=B.UserId AND A.IsDel=0 AND B.IsDel=0 WHERE A.IsDel=0

但上面这条语句比较逻辑,也完全没必要这么写,因此我的建议是:针对单表字段构成的筛选条件这种情况,最好的做法是直接将条件放到WHERE子句中。

转载于:https://www.cnblogs.com/shoter193/p/3595962.html

<think>好的,用户现在想了解SQL Server中的LEFT OUTER JOIN。我需要先回顾一下之前他问过的问题,之前他问过DATEDIFF,现在转向JOIN类型,可能是在学习SQL的不同部分。 首先,用户可能已经了解基本的JOIN概念,但需要明确LEFT OUTER JOIN的具体用法。我应该先定义LEFT OUTER JOIN的作用,强调它返回左表所有记录和右表匹配的记录,如果没有匹配,右表部分为NULL。 接下来,用户可能需要语法示例,这样他们可以直观地看到怎么写这个JOIN。要提供一个标准的语法结构,并解释每个部分的含义,比如ON子句的作用。 然后,对比LEFT OUTER JOIN和INNER JOIN区别很重要。用户可能混淆这两者,特别是刚学习的时候。用具体的例子说明两者的不同,比如当右表没有匹配时,INNER JOIN会排除左表的记录,而LEFT OUTER JOIN会保留。 实际应用场景能帮助用户理解何时使用这个JOIN。比如统计所有客户的订单,即使没有订单的客户也要显示,这时候LEFT OUTER JOIN就很有用。可能需要举一个具体的例子,包括表结构和查询语句,以及结果说明。 此外,用户可能对多个表的JOIN操作感兴趣,或者对性能有疑问。不过根据当前问题,可能不需要深入讨论性能优化,但可以提到在使用时需要注意索引和条件优化。 还要注意LEFT OUTER JOIN中的过滤条件位置,比如WHEREON区别,这是一个常见的误区。比如在ON里过滤会影响JOIN结果,而在WHERE中则是在JOIN之后过滤,可能导致不同的结果。 最后,是否需要提及其他JOIN类型的比较,比如RIGHT OUTER JOIN或FULL OUTER JOIN?可能简要提一下,但重点还是放在LEFT OUTER JOIN上。 总结一下,回答的结构应该是:定义、语法、INNER JOIN区别、应用场景、注意事项、示例。确保用中文清晰解释,避免术语混乱,并举例说明。检查是否有遗漏点,比如别名使用、多表连接,或者常见错误,比如条件放错位置。</think>### SQL Server 的 `LEFT OUTER JOIN` 逐步解析 `LEFT OUTER JOIN`(左外连接)是 SQL 中用于**关联两个表**的查询操作,其核心规则是:**保留左表的所有行,并匹配右表中符合条件的行;若无匹配,右表字段以 `NULL` 填充**。以下是详细解析: --- ### 一、基本语法 ```sql SELECT 列名 FROM 左表 LEFT OUTER JOIN 右表 ON 左表.关联列 = 右表.关联列; ``` - **关键字**:`LEFT OUTER JOIN`(可简写为 `LEFT JOIN`) - **ON 子句**:定义两个表的关联条件 - **结果**: - 左表所有行必然出现在结果中 - 右表仅返回匹配的行,无匹配时填充 `NULL` --- ### 二、 `INNER JOIN` 的区别 | 特性 | LEFT OUTER JOIN | INNER JOIN | |---------------------|-------------------------------------|--------------------------------| | **左表未匹配的行** | 保留,右表字段为 `NULL` | 不保留 | | **右表未匹配的行** | 不保留(除非右表有其他关联条件) | 不保留 | | **结果集大小** | ≥ 左表行数 | ≤ 左表行数 | --- ### 三、典型应用场景 #### 1. **查询主表数据并关联补充信息** - **示例**:列出所有客户及其订单(即使客户没有订单) ```sql SELECT Customers.CustomerName, Orders.OrderID FROM Customers LEFT JOIN Orders ON Customers.CustomerID = Orders.CustomerID; ``` - 结果包含所有客户,无订单的客户其 `OrderID` 为 `NULL`。 #### 2. **统计存在/不存在关联的记录** - **示例**:找出未下单的客户 ```sql SELECT Customers.CustomerName FROM Customers LEFT JOIN Orders ON Customers.CustomerID = Orders.CustomerID WHERE Orders.OrderID IS NULL; ``` --- ### 四、注意事项 1. **关联条件位置**: - 过滤条件写在 `ON` 子句中:影响匹配逻辑(在关联时过滤右表) - 过滤条件写在 `WHERE` 子句中:在关联完成后过滤最终结果 2. **性能优化**: - 为关联列(如 `CustomerID`)添加索引 - 避免在右表中使用复杂条件导致全表扫描 3. **多表连接**: - 可链式使用多个 `LEFT JOIN`,但需注意顺序对结果的影响 ```sql SELECT * FROM TableA LEFT JOIN TableB ON TableA.ID = TableB.A_ID LEFT JOIN TableC ON TableB.ID = TableC.B_ID; ``` --- ### 五、示例演示 #### 表结构 - **`Employees` 表**: | EmployeeID | Name | |------------|--------| | 1 | 张三 | | 2 | 李四 | - **`Orders` 表**: | OrderID | EmployeeID | Amount | |---------|------------|--------| | 101 | 1 | 200 | | 102 | 1 | 300 | #### 查询 ```sql SELECT Employees.Name, Orders.OrderID, Orders.Amount FROM Employees LEFT JOIN Orders ON Employees.EmployeeID = Orders.EmployeeID; ``` #### 结果 | Name | OrderID | Amount | |--------|---------|--------| | 张三 | 101 | 200 | | 张三 | 102 | 300 | | 李四 | NULL | NULL | --- ### 六、总结 `LEFT OUTER JOIN` 是处理**主从表关联**或**保留主表完整数据**的核心工具。使用时需明确: 1. 是否需要保留左表全部数据 2. 关联条件的准确性 3. 性能影响(尤其是大数据量场景)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值