Azure环境下T-SQL连接查询中AND与WHERE的逻辑差异咨询
嘿,这个问题其实是T-SQL里连接查询的经典坑点之一,我来给你掰扯清楚~
为什么WHERE和ON子句中的AND有时结果一致,有时却不同?
1. 内连接(INNER JOIN)场景:结果一致是正常操作
你测试的JOIN(默认就是内连接)里,把ca.addressType = 'Main Office'放在WHERE里或者加到ON子句的AND后面,结果确实会一模一样。原因很简单:内连接的逻辑是只保留两张表中完全匹配ON条件的行,不管你是先在ON里过滤关联表的行再匹配,还是先匹配所有符合c.customerID = ca.customerID的行再用WHERE过滤,最终留下来的都是同时满足两个条件的行。
比如你的示例语句,两种写法完全等价:
-- 写法1:WHERE过滤 select c.customerID, ca.addressID, ca.addressType from salesLT.customer as c join salesLT.customerADdress as ca on c.customerID = ca.customerID WHERE ca.addressType = 'Main Office';
-- 写法2:ON子句加AND过滤 select c.customerID, ca.addressID, ca.addressType from salesLT.customer as c join salesLT.customerADdress as ca on c.customerID = ca.customerID AND ca.addressType = 'Main Office';
甚至数据库优化器可能会生成完全相同的执行计划,性能上没差别。
2. 外连接(LEFT/RIGHT/FULL JOIN)场景:WHERE和ON的AND天差地别
这就是你说的“WHERE无法生效而AND可行”的核心场景——当你用外连接的时候,两者的逻辑完全不同:
- ON子句里的AND:是用来筛选要关联的表的行,但主表(比如左连接里的左表)的所有行都会被保留,关联表中不匹配条件的行则会显示为NULL。
- WHERE子句:是在连接完成之后对整个结果集进行过滤,这时候如果关联表的列(比如
ca.addressType)是NULL的话,WHERE ca.addressType = 'Main Office'会把这些主表的行也删掉,相当于把外连接直接变成了内连接。
举个左连接的例子对比,你就能一眼看出区别:
-- 写法1:ON子句加AND,保留所有客户行,无Main Office地址的客户对应address列显示NULL select c.customerID, ca.addressID, ca.addressType from salesLT.customer as c left join salesLT.customerADdress as ca on c.customerID = ca.customerID AND ca.addressType = 'Main Office';
-- 写法2:WHERE过滤,会直接删掉没有Main Office地址的客户行 select c.customerID, ca.addressID, ca.addressType from salesLT.customer as c left join salesLT.customerADdress as ca on c.customerID = ca.customerID WHERE ca.addressType = 'Main Office';
第一种写法会返回所有客户,哪怕某个客户没有Main Office类型的地址;第二种写法则只返回那些有Main Office地址的客户——这就是你觉得“WHERE无法生效”的原因,其实不是不生效,是它的逻辑和你预期的(保留主表所有行)完全不一样。
总结一下
- 内连接时,两种写法结果一致,选哪种看个人习惯(不过把关联条件放ON、过滤条件放WHERE,更符合代码可读性规范)。
- 外连接时,一定要区分:如果想筛选关联表的行但保留主表所有行,就把条件加在ON的AND后面;如果想过滤整个结果集(包括删掉主表中没有匹配的行),就用WHERE。
内容的提问来源于stack exchange,提问作者Hana
相关产品推荐
相关产品推荐

