Dlaczego i kiedy lewy JOIN with condition in WHERE nie jest równoznaczny z tym samym lewym JOIN in ON? [duplikat]
To pytanie ma już odpowiedź tutaj:
- SQL join: where klauzula vs. on klauzula 14 odpowiedzi
- różnica między " on .. i " i " dalej .. gdzie " w SQL LEFT Join? 5 odpowiedzi
Doświadczam bardzo zagmatwanej sytuacji to sprawia, że kwestionuję całe moje zrozumienie łączy w SQL Server.
SELECT t1.f2
FROM t1
LEFT JOIN t2
ON t1.f1 = t2.f1 AND cond2 AND t2.f3 > something
Nie daje takich samych wyników jak:
SELECT t1.f2
FROM t1
LEFT JOIN t2
ON t1.f1 = t2.f1 AND cond2
WHERE t2.f3 > something
Czy ktoś może pomóc, mówiąc, czy te dwa pytania mają być równoważne, czy nie?
Thx
5 answers
Klauzula on
jest używana, gdy join
szuka pasujących wierszy. Klauzula where
służy do filtrowania wierszy po zakończeniu łączenia.
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
mimo, że Donald
nie głosowało na niego. Jeśli przeniesiesz warunek z {[2] } do where
klauzuli:
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.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-29 15:29:53
Oba są dosłownie różne.
Pierwsze zapytanie wykonuje filtrowanie tabeli t2
przed połączeniem tabel. Tak więc wyniki zostaną dołączone do tabeli t1
w wyniku czego wszystkie rekordy t1
zostaną pokazane na liście.
Drugi filtruje wynik 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 pierwszym zapytaniu wygląda to tak: to,
SELECT a.*, b.Score
FROM Table1 a
LEFT JOIN Table2 b
ON a.ID = b.T1_ID AND
b.Score >= 20
To, co robi przed dołączeniem do tabel, rekordy {[11] } są filtrowane najpierw przez wynik. Tak więc jedynymi rekordami, które zostaną dołączone do table1 są
T1_ID Score
2 20
3 30
Ponieważ Score
z T1_ID
jest tylko 10. Wynikiem zapytania jest
ID Name Score
1 Stack NULL
2 Over 20
3 Flow 30
Podczas gdy drugie zapytanie jest inne.
SELECT a.*, b.Score
FROM Table1 a
LEFT JOIN Table2 b
ON a.ID = b.T1_ID
WHERE b.Score >= 20
Najpierw dołącza do rekordów, czy ma pasujący rekord na drugiej tabeli lub nie. Więc wynik będzie
ID Name Score
1 Stack 10
2 Over 20
3 Flow 30
I filtrowanie odbywa się b.Score >= 20
. Tak więc końcowy wynik będzie
ID Name Score
2 Over 20
3 Flow 30
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-29 15:37:51
W pierwszym przypadku wyniki w {[0] } są filtrowane jako część połączenia.
W drugim przypadku może być więcej wierszy dostępnych od t2
.
Zasadniczo zestaw rekordów połączonych w dwóch zapytaniach nie będzie taki sam.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-29 15:21:19
To robi różnicę, ponieważ w drugim przypadku stosujesz where po lewej stronie
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-29 15:22:00
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'
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-29 15:41:47