2013-03-29 16 views
18

Występuje bardzo myląca sytuacja, która sprawia, że ​​kwestionuję wszystkie moje rozumienie sprzężeń w SQL Server.Dlaczego i kiedy LEFT JOIN z warunkiem w klauzuli WHERE nie jest równoznaczne z tym samym LEWYM DOŁĄCZEM w położeniu ON?

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

nie daje takie same wyniki jak:

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

można zadowolić kogoś pomoc mówiąc, jeśli te dwa pytania mają być równoważne, czy nie?

Thx

+2

Opcja 'ON' zmniejsza zbiór wierszy, które są połączone, podczas gdy' WHERE' zmniejsza zbiór wierszy, które są dodawane do zestawu wyników ... – Lucas

+2

nie są one równoważne. Twoje pierwsze zapytanie filtruje wyniki w złączeniu; drugi filtruje * po *. –

+0

Nie jestem pewien, czy pytania są równoważne, ponieważ tutaj warunek jest wyrażony na drugiej tabeli .. –

Odpowiedz

30

Klauzula on jest używany, gdy join szuka pasujących wierszy. Klauzula where służy do filtrowania wierszy po zakończeniu łączenia.

Przykładem z Disney Toons głosowanie na prezydenta:

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' 

To wciąż powraca Romney chociaż Donald nie głosować na niego. Jeśli przesuniesz stan z on klauzuli where:

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

Romney nie będzie już w zestawie wyników.

+1

Należy zauważyć, że w tym przykładzie zastosowano sprzężenie zewnętrzne, co ma miejsce w przypadku, gdy te dwa fragmenty kodu nie są funkcjonalnie równoważne. –

+0

Szukałem czegoś zupełnie innego, ale jakoś go mnie tu zaprowadziło a twoja pięść dwa zdania uratowały mój dzień! Dziękujemy +1! – ksno

0

W pierwszym przypadku, powoduje t2 sączy w ramach sprzężenia.

W drugim przypadku może być dostępnych więcej wierszy od t2.

Zasadniczo zestaw rekordów połączonych w dwóch zapytaniach nie będzie taki sam.

0

To robi różnicę, ponieważ w drugim przypadku, gdy zastosowanie gdzie po to robi lewa dołączyć

17

Oba są dosłownie inna.

Pierwsze zapytanie filtruje tabelę t2 przed przystąpieniem do tabel. Wyniki zostaną następnie dołączone do tabeli t1, co spowoduje wyświetlenie wszystkich rekordów t1 na liście.

Drugi odfiltrowuje z łącznego wyniku po zakończeniu łączenia tabel.


Oto przykład

Table1

ID Name 
1 Stack 
2 Over 
3 Flow 

Table2

T1_ID Score 
1  10 
2  20 
3  30 

W swojej pierwszej kwerendy, wygląda to tak,

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

Co robi się przed przystąpieniem do tabel, zapisy table2 są filtrowane najpierw przez wynik. Więc tylko rekordy, które będą połączone na tabela1 są

T1_ID Score 
2  20 
3  30 

ponieważ Score od T1_ID jest tylko 10.Wynikiem zapytania jest

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

Choć drugie zapytanie jest inna.

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

Najpierw łączy zapisy, czy ma odpowiadający rekord na drugim stole, czy nie. Więc wynik będzie

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

i filtrowanie odbywa b.Score >= 20. Tak więc końcowy wynik będzie

ID Name Score 
2 Over 20 
3 Flow 30 
+0

Dobrze wyjaśnione! –

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'