为什么以及何时在WHERE子句中与LEFT JOIN条件不等同于ON中的相同LEFT JOIN?

我遇到一个非常混乱的情况,这让我质疑我对SQL Server连接的理解。

SELECT t1.f2 FROM t1 LEFT JOIN t2 ON t1.f1 = t2.f1 AND cond2 AND t2.f3 > something 

不会给出与以下相同的结果:

 SELECT t1.f2 FROM t1 LEFT JOIN t2 ON t1.f1 = t2.f1 AND cond2 WHERE t2.f3 > something 

可以请人帮忙告诉这两个查询是否应该是相当的?

谢谢

on子句用于join查找匹配的行时。 在所有连接完成后, where子句用于过滤行。

迪士尼乐园投票给总统的一个例子:

 declare @candidates table (name varchar(50)); insert @candidates values ('Obama'), ('Romney'); declare @votes table (voter varchar(50), voted_for varchar(50)); insert @votes values ('Mickey Mouse', 'Romney'), ('Donald Duck', 'Obama'); select * from @candidates c left join @votes v on c.name = v.voted_for and v.voter = 'Donald Duck' 

即使Donald没有投票给Romney这仍然会回来。 如果将条件从on移到where子句:

 select * from @candidates c left join @votes v on c.name = v.voted_for where v.voter = 'Donald Duck' 

Romney将不再在结果集中。

两者是完全不同的。

第一个查询在发生表连接之前进行表t2的过滤。 所以结果将被join到表t1上,结果t1所有logging将被显示在列表中。

第二个从join表完成后的总结果过滤。


这是一个例子

表格1

 ID Name 1 Stack 2 Over 3 Flow 

表2

 T1_ID Score 1 10 2 20 3 30 

在你的第一个查询中,它看起来像这样,

 SELECT a.*, b.Score FROM Table1 a LEFT JOIN Table2 b ON a.ID = b.T1_ID AND b.Score >= 20 

在join表之前, table2的logging首先被分数过滤。 所以在table1上唯一的logging是

 T1_ID Score 2 20 3 30 
  • SQLFiddle演示

因为T1_IDScore只有10个。查询的结果是

 ID Name Score 1 Stack NULL 2 Over 20 3 Flow 30 
  • SQLFiddle演示

而第二个查询是不同的。

 SELECT a.*, b.Score FROM Table1 a LEFT JOIN Table2 b ON a.ID = b.T1_ID WHERE b.Score >= 20 

它首先joinlogging是否在另一张桌子上有匹配的logging。 所以结果会是

 ID Name Score 1 Stack 10 2 Over 20 3 Flow 30 
  • SQLFiddle演示

并进行过滤b.Score >= 20 。 所以最终的结果将是

 ID Name Score 2 Over 20 3 Flow 30 
  • SQLFiddle演示

在第一种情况下, t2结果将作为连接的一部分进行过滤。

在第二种情况下,从t2可能有更多的行。

实质上,在两个查询中join的logging集不会相同。

 CREATE TABLE Company ( CompanyId TinyInt Identity Primary Key, CompanyName Nvarchar(50) NULL ) GO INSERT Company VALUES('DELL') INSERT Company VALUES('HP') INSERT Company VALUES('IBM') INSERT Company VALUES('Microsoft') GO CREATE TABLE Candidate ( CandidateId tinyint identity primary key, FullName nvarchar(50) NULL, CompanyId tinyint REFERENCES Company(CompanyId) ) GO INSERT Candidate VALUES('Ron',1) INSERT Candidate VALUES('Pete',2) INSERT Candidate VALUES('Steve',3) INSERT Candidate VALUES('Steve',NULL) INSERT Candidate VALUES('Ravi',1) INSERT Candidate VALUES('Raj',3) INSERT Candidate VALUES('Kiran',NULL) GO SELECT * from Company c SELECT * from Candidate c -- A simple left outer Join SELECT * FROM Company c LEFT OUTER JOIN Candidate c2 ON c.CompanyId = c2.CompanyId --Left Outer Join ON and AND condition fetches 5 rows wtih NULL value from right side table SELECT * FROM Company c LEFT OUTER JOIN Candidate c2 ON c.CompanyId = c2.CompanyId AND c.CompanyName = 'DELL' --Left Outer Join ON and where clause fetches only required rows SELECT * FROM Company c LEFT OUTER JOIN Candidate c2 ON c.CompanyId = c2.CompanyId AND c.CompanyName = 'DELL' WHERE c.CompanyName='IBM' 

它确实有所作为,因为在第二种情况下,您正在应用其后进行左连接的位置