it-swarm.com.de

Warum und wann ist ein LEFT JOIN mit Bedingung in der WHERE-Klausel nicht gleich LEFT JOIN in ON?

Ich habe eine sehr verwirrende Situation, die mich mein Verständnis von Joins in SQL Server in Frage stellt.

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

Ergibt nicht die gleichen Ergebnisse wie:

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

Kann mir bitte jemand helfen, indem er sagt, ob diese beiden Anfragen gleichwertig sein sollen oder nicht?

Vielen Dank

18
Kamel Keb

Die on-Klausel wird verwendet, wenn die join nach übereinstimmenden Zeilen sucht. Die where-Klausel wird verwendet, um Zeilen zu filtern, nachdem alle Verknüpfungen abgeschlossen sind.

Ein Beispiel, bei dem Disney Toons für den Präsidenten stimmen:

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'

Dies gibt immer noch Romney zurück, auch wenn Donald nicht für ihn gestimmt hat. Wenn Sie die Bedingung von der Variable on in die Klausel where verschieben:

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

Romney ist nicht mehr in der Ergebnismenge enthalten.

32
Andomar

Beide sind buchstäblich verschieden.

Bei der ersten Abfrage wird die Tabelle t2 gefiltert, bevor die Tabellen zusammengefügt werden. Die Ergebnisse werden dann in der Tabelle t1 zusammengefügt, wodurch alle Datensätze von t1 in der Liste angezeigt werden.

Der zweite Filter wird aus dem Gesamtergebnis herausgefiltert, nachdem die Tabellen zusammengefügt wurden.


Hier ist ein Beispiel

Tabelle 1

ID   Name
1    Stack
2    Over 
3    Flow

Tabelle 2

T1_ID   Score
1       10
2       20
3       30

In Ihrer ersten Abfrage sieht es so aus,

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

Vor dem Zusammenfügen der Tabellen werden die Datensätze von table2 zuerst nach der Bewertung gefiltert. Die einzigen Datensätze, die auf table1 verbunden werden, sind also

T1_ID   Score
2       20
3       30

weil die Score von T1_ID nur 10 ist. Das Ergebnis der Abfrage ist 

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

Während die zweite Abfrage anders ist.

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

Er fügt die Datensätze zuerst hinzu, unabhängig davon, ob in der anderen Tabelle ein übereinstimmender Datensatz vorhanden ist oder nicht. Das Ergebnis wird also sein

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

und die Filterung erfolgt b.Score >= 20. Das Endergebnis wird also sein

ID   Name    Score
2    Over    20
3    Flow    30
17
John Woo

Im ersten Fall werden die Ergebnisse in t2 als Teil des Joins gefiltert.

Im zweiten Fall könnten unter t2 weitere Zeilen verfügbar sein. 

Grundsätzlich ist die Menge der Datensätze, die in den beiden Abfragen verknüpft sind, nicht gleich.

0
Ryan

Es macht einen Unterschied, weil Sie im zweiten Fall den Bereich anwenden, NACHDEM er den linken Join durchführt

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