为什么以及何时在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_ID
的Score
只有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'
它确实有所作为,因为在第二种情况下,您正在应用其后进行左连接的位置