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
この2つのクエリが同等であるかどうかを伝えることで誰かが助けてくれますか?
THX
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
は結果セットに含まれなくなります。
両方とも文字通り異なります。
最初のクエリは、テーブルの結合が行われる前に、テーブルt2
のフィルタリングを実行します。したがって、結果はテーブルt1
に結合され、t1
のすべてのレコードがリストに表示されます。
2番目は、テーブルの結合が完了した後の合計結果からフィルタリングします。
ここに例があります
表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
のレコードがスコアによって最初にフィルター処理されます。したがって、table1で結合される唯一のレコードは
T1_ID Score
2 20
3 30
T1_ID
のScore
は10のみであるためです。クエリの結果は
ID Name Score
1 Stack NULL
2 Over 20
3 Flow 30
2番目のクエリは異なりますが。
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
最初のケースでは、t2
は、結合の一部としてフィルタリングされます。
2番目のケースでは、t2
。
基本的に、2つのクエリで結合されたレコードのセットは同じではありません。
2番目のケースでは、左結合を行った後にwhereを適用しているため、違いが生じます。
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'