2013-03-29 77 views
18

我遇到一個非常混亂的情況,這讓我質疑我對SQL Server連接的全部理解。爲什麼以及WHERE子句中的LEFT JOIN與條件不等於ON中的相同LEFT JOIN?

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 

可以通過,如果這兩個查詢都應該是相等的或不告訴請人幫助嗎?

THX

+2

的'ON'減少那些正在參加行,而'WHERE'降低了集添加到結果集中的行... – Lucas

+2

他們是不等價的。你的第一個查詢過濾了連接中的結果; *之後的第二個過濾器*。 –

+0

我不確定問題是否相同,因爲這裏,條件表示在第二張表上。 –

回答

30

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' 

這仍然返回Romney即使Donald沒有投他的票。如果從on移動狀態的where條款:

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

Romney將不再在結果集中。

+1

請注意,此示例使用的是外部連接,在這種情況下,這兩個代碼片段在功能上並不等效。 –

+0

我正在尋找完全不同的東西,但不知何故,谷歌帶我到這裏,你的拳頭兩句句子拯救了我的一天!謝謝+1! – ksno

0

在第一情況下,導致t2被過濾爲一體的連接部分。

在第二種情況下,t2可能有更多行可用。

實質上,在兩個查詢中加入的記錄集不會相同。

0

它確實有差別,因爲在第二種情況下,你所申請後,確實在那裏的左連接

17

兩者都是從字面上不同。

第一個查詢在進行表連接之前進行表t2的過濾。所以結果將被加入表t1,導致所有記錄t1將顯示在列表中。

第二個從加入表格後的總結果過濾完成。


下面是一個例子

表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 

它在加入表之前,首先按照得分過濾table2的記錄。因此,將表1上被連接的唯一記錄

T1_ID Score 
2  20 
3  30 

因爲T1_IDScore只有10。查詢的結果是

ID Name Score 
1 Stack NULL 
2 Over 20 
3 Flow 30 

而第二個查詢是不同的。

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

它首先加入記錄是否在另一張桌子上有匹配的記錄。因此,其結果將是

ID Name Score 
1 Stack 10 
2 Over 20 
3 Flow 30 

和過濾發生b.Score >= 20。所以最終的結果將是

ID Name Score 
2 Over 20 
3 Flow 30 
+0

很好解釋! –

0
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'