Wie kann ein LEFT OUTER JOIN mehr Datensätze zurückgeben, als in der linken Tabelle vorhanden sind?

164

Ich habe einen sehr einfachen LEFT OUTER JOIN, um alle Ergebnisse aus der linken Tabelle und einige zusätzliche Informationen aus einer viel größeren Tabelle zurückzugeben. Die linke Tabelle enthält 4935 Datensätze. Wenn ich sie jedoch einer zusätzlichen Tabelle beitrete, ist die Anzahl der Datensätze erheblich größer.

Soweit mir bekannt ist, ist es ein absolutes Evangelium, dass ein LEFT OUTER JOIN alle Datensätze aus der linken Tabelle mit übereinstimmenden Datensätzen aus der rechten Tabelle und Nullwerten für alle Zeilen zurückgibt, die nicht übereinstimmen können. Daher verstehe ich, dass dies der Fall sein sollte Es ist unmöglich, mehr Zeilen zurückzugeben, als in der linken Tabelle vorhanden sind, aber es passiert trotzdem!

SQL Query folgt:

SELECT     SUSP.Susp_Visits.SuspReason, SUSP.Susp_Visits.SiteID
FROM         SUSP.Susp_Visits LEFT OUTER JOIN
                      DATA.Dim_Member ON SUSP.Susp_Visits.MemID = DATA.Dim_Member.MembershipNum

Vielleicht habe ich einen Fehler in der Syntax gemacht oder mein Verständnis von LEFT OUTER JOIN ist unvollständig, hoffentlich kann jemand erklären, wie dies geschehen könnte?

Nachtrag

Vielen Dank für die tollen Antworten. Mein Verständnis von LEFT OUTER JOINS ist jetzt viel besser. Kann jemand jedoch vorschlagen, wie diese Abfrage so geändert werden kann, dass nur so viele Datensätze zurückgegeben werden, wie in der linken Tabelle vorhanden sind?

Diese Abfrage dient lediglich dazu, einen Bericht zu erstellen, und die doppelten Übereinstimmungen verwirren die Sache einfach.

/ Postscript

Jay Wilde
quelle
5
Um "so viele Datensätze zurückzugeben, wie in der linken Tabelle vorhanden sind", müssen Sie angeben, welche Zeile auf der rechten Seite ausgewählt werden soll, wenn mehrere Übereinstimmungen vorhanden sind.
AK
1
Wie spezifizierst du das? Ich möchte, dass das erste Spiel zurückgegeben wird.
Simon Cross
1
Sie müssen definieren, was mit der ersten Übereinstimmung gemeint ist. Möchten Sie die früheste Aufzeichnung, die mit der höchsten ID oder was?
HLGEM
1
Wenn Sie mit dem Primärschlüssel in einer zusätzlichen Tabelle übereinstimmen, ist Ihre Aussage korrekt.
Prageeth Godage
Ich benutze oft eine Ressource wie dies als Spickzettel , wenn Abfragen zu bauen. Wenn der Link jemals stirbt, gehen Sie einfach auf Google SQL Join . Es handelt sich um Venn-Diagramme der verschiedenen Arten von Verknüpfungen.
Zimano

Antworten:

189

Der LEFT OUTER JOIN gibt nach Möglichkeit alle Datensätze aus der LEFT-Tabelle zurück, die mit der RIGHT-Tabelle verknüpft sind.

Wenn es jedoch Übereinstimmungen gibt, werden weiterhin alle übereinstimmenden Zeilen zurückgegeben. Daher wird eine Zeile in LINKS, die mit zwei Zeilen in RECHTS übereinstimmt, wie ein INNER JOIN als zwei REIHEN zurückgegeben.

BEARBEITEN: Als Antwort auf Ihre Bearbeitung habe ich mir gerade Ihre Abfrage genauer angesehen und es sieht so aus, als würden Sie nur Daten aus der Tabelle LINKS zurückgeben. Wenn Sie also nur Daten aus der LEFT-Tabelle und nur eine Zeile für jede Zeile in der LEFT-Tabelle zurückgeben möchten, müssen Sie überhaupt keinen JOIN ausführen und können einfach SELECT direkt aus der LEFT-Tabelle ausführen.

Robin Day
quelle
1
Der Grund für den Beitritt zum rechten Tisch war, dass ich nur Datensätze von links bekam, wo sich mindestens ein Datensatz in der rechten Tabelle befand, aber vielen Dank für die Erklärung.
Jay Wilde
125
Table1                Table2
_______               _________
1                      2
2                      2
3                      5
4                      6

SELECT Table1.Id, Table2.Id FROM Table1 LEFT OUTER JOIN Table2 ON Table1.Id=Table2.Id

Ergebnisse:

1,null
2,2
2,2
3,null
4,null
Andrew Lewis
quelle
1
So einfach und doch so mächtig.
Kiradotee
39

Das ist nicht unmöglich. Die Anzahl der Datensätze in der linken Tabelle entspricht der Mindestanzahl der zurückgegebenen Datensätze. Wenn die rechte Tabelle zwei Datensätze enthält, die mit einem Datensatz in der linken Tabelle übereinstimmen, werden zwei Datensätze zurückgegeben.

HLGEM
quelle
12

Als Antwort auf Ihr Postskriptum hängt das davon ab, was Sie möchten.

Sie erhalten (mögliche) mehrere Zeilen für jede Zeile in Ihrer linken Tabelle, da es mehrere Übereinstimmungen für die Verknüpfungsbedingung gibt. Wenn Sie möchten, dass Ihre Gesamtergebnisse die gleiche Anzahl von Zeilen aufweisen wie im linken Teil der Abfrage, müssen Sie sicherstellen, dass Ihre Verknüpfungsbedingungen eine 1: 1-Übereinstimmung verursachen.

Abhängig davon, was Sie tatsächlich möchten, können Sie alternativ Aggregatfunktionen verwenden (wenn Sie beispielsweise nur eine Zeichenfolge aus dem rechten Teil möchten, können Sie eine Spalte generieren, die eine durch Kommas getrennte Zeichenfolge der Ergebnisse auf der rechten Seite für diese linke Zeile ist.

Wenn Sie nur 1 oder 2 Spalten aus dem äußeren Join betrachten, können Sie eine skalare Unterabfrage verwenden, da Ihnen 1 Ergebnis garantiert wird.

Chris Cameron-Mills
quelle
4
Dies ist eine gute Antwort, da sie Vorschläge enthält, wie nur Zeilen aus der linken Tabelle zurückgegeben werden können.
Karns
9

Jeder Datensatz aus der linken Tabelle wird so oft zurückgegeben, wie übereinstimmende Datensätze in der rechten Tabelle vorhanden sind - mindestens 1, kann aber leicht mehr als 1 betragen.

Alex Martelli
quelle
8

LEFT OUTER JOIN gibt genau wie INNER JOIN (normaler Join) für jede Zeile in der linken Tabelle so viele Ergebnisse zurück, wie viele Übereinstimmungen in der rechten Tabelle gefunden wurden. Daher können Sie viele Ergebnisse erzielen - bis zu N x M, wobei N die Anzahl der Zeilen in der linken Tabelle und M die Anzahl der Zeilen in der rechten Tabelle ist.

Es ist die Mindestanzahl von Ergebnissen, die in LEFT OUTER JOIN immer garantiert mindestens N beträgt.

Spitzenkoch
quelle
1
Ich begann zu überlegen, wann die Anzahl der Zeilen gleich N x M ist und die einzige reale Situation, die mir in den Sinn kommt, ist, wenn N oder M gleich 1 sind. Stimmen Sie zu?
BartoszMiller
2
Nein, ich nicht. Sie sollten sich die Join-Bedingung nicht nur als Key Equality Join vorstellen. Dies kann eine beliebige Bedingung sein, z. B. Datumsbereiche, Ungleichungen usw. Zwei Extremfälle: (a) N Zeilen haben keine einzige Übereinstimmung zwischen M Zeilen, und die linke äußere Verknüpfung führt zu N Zeilen, die mit NULL übereinstimmen. (b) jede der N Zeilen stimmt mit allen M Zeilen überein, dann wird das Ergebnis N x M Zeilen gesetzt.
Topchef
1
Sie haben Recht, ich habe über Joins nur im Hinblick auf die Schlüsselgleichheit nachgedacht. Ich mag Ihr Beispiel aus "Fall b". Ich glaube, dass "jede von N Zeilen mit allen M Zeilen übereinstimmt" ein allgemeines Rezept für die Rückgabe von N x M Zeilen ist, was eher unmöglich zu visualisieren ist, wenn man nur an die Schlüsselgleichheit denkt.
BartoszMiller
7

Könnte es eine Eins-zu-Viele-Beziehung zwischen der linken und der rechten Tabelle sein?

Ken Burkhardt
quelle
6

Achten Sie darauf, wenn Sie eine where-Klausel in der Tabelle "rechte Seite" einer Abfrage haben, die einen linken äußeren Join enthält ... Falls Sie auf der rechten Seite keinen Datensatz haben, der die where-Klausel erfüllt, dann den entsprechenden Datensatz der linken Seite 'Tabelle wird nicht im Ergebnis Ihrer Abfrage angezeigt ....

Serge
quelle
1
Sie sollten dann die Bedingung zur ON-Klausel des entsprechenden LEFT OUTER JOIN hinzufügen.
Mik
6

Wenn Sie nur eine Reihe von der rechten Seite benötigen

SELECT SuspReason, SiteID FROM(
    SELECT SUSP.Susp_Visits.SuspReason, SUSP.Susp_Visits.SiteID, ROW_NUMBER()
    OVER(PARTITION BY SUSP.Susp_Visits.SiteID) AS rn
    FROM SUSP.Susp_Visits
    LEFT OUTER JOIN DATA.Dim_Member ON SUSP.Susp_Visits.MemID = DATA.Dim_Member.MembershipNum
) AS t
WHERE rn=1

oder nur

SELECT SUSP.Susp_Visits.SuspReason, SUSP.Susp_Visits.SiteID
FROM SUSP.Susp_Visits WHERE EXISTS(
    SELECT DATA.Dim_Member WHERE SUSP.Susp_Visits.MemID = DATA.Dim_Member.MembershipNum
)
AK
quelle
1
Da Sie DDL und DML nicht angegeben haben, habe ich nicht getestet. Jedenfalls denke ich, dass EXISTS das ist, was du willst. Versuchen Sie Folgendes: SELECT SuspReason, SiteID FROM (SELECT SUSP.Susp_Visits.SuspReason, SUSP.Susp_Visits.SiteID, ROW_NUMBER () OVER (PARTITION BY SUSP.Susp_Visits.SiteID ORDER BY SUSP.Susp_Visits.SiteS JOIN DATA.Dim_Member ON SUSP.Susp_Visits.MemID = DATA.Dim_Member.MembershipNum) AS t WHERE rn = 1
AK
2

Es scheint, als ob die Tabelle DATA.Dim_Member mehrere Zeilen pro Zeile SUSP.Susp_Visits enthält.

bdukes
quelle
2

Wenn mehrere (x) Zeilen in Dim_Member einer einzelnen Zeile in Susp_Visits zugeordnet sind, enthält die Ergebnismenge x Zeilen.

Manu
quelle