W jaki sposób LEFT OUTER JOIN może zwrócić więcej rekordów niż istnieje w lewej tabeli?

165

Mam bardzo podstawowe LEFT OUTER JOIN, aby zwrócić wszystkie wyniki z lewej tabeli i kilka dodatkowych informacji ze znacznie większej tabeli. Lewa tabela zawiera 4935 rekordów, ale kiedy opuściłem OUTER JOIN do dodatkowej tabeli, liczba rekordów jest znacznie większa.

O ile wiem, jest absolutną ewangelią, że LEFT OUTER JOIN zwróci wszystkie rekordy z lewej tabeli z dopasowanymi rekordami z prawej tabeli i wartościami zerowymi dla wszystkich wierszy, których nie można dopasować, jako takie rozumiem, że powinno zwrócenie większej liczby wierszy niż istnieje w tabeli po lewej stronie jest niemożliwe, ale to się dzieje tak samo!

Zapytanie SQL następuje:

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

Być może popełniłem błąd w składni lub moje rozumienie LEFT OUTER JOIN jest niekompletne, mam nadzieję, że ktoś może wyjaśnić, jak to się dzieje?

Postscriptum

Dzięki za świetne odpowiedzi, moje rozumienie LEFT OUTER JOINS jest teraz znacznie lepsze. Czy ktokolwiek mógłby jednak zasugerować sposób zmodyfikowania tego zapytania, aby uzyskać tylko tyle zwróconych rekordów, ile istnieje w lewej tabeli?

To zapytanie służy wyłącznie do wygenerowania raportu, a zduplikowane dopasowania po prostu komplikują sprawę.

/Postscriptum

Jay Wilde
źródło
5
Aby „pobrać tyle rekordów, ile istnieje w lewej tabeli”, musisz określić, który wiersz z prawej strony ma zostać wybrany, jeśli występuje wiele dopasowań.
AK
1
jak to określisz? Chciałbym zwrócić pierwszą zapałkę.
Simon Cross
1
musisz zdefiniować, co oznacza pierwsze dopasowanie. Chcesz najwcześniejszy rekord, ten z najwyższym identyfikatorem, czy co?
HLGEM
1
Jeśli dopasujesz klucz podstawowy w dodatkowej tabeli, to stwierdzenie jest poprawne.
Prageeth godage
Często używam zasobu jak to jako ściągawki podczas budowania zapytań. Jeśli link kiedykolwiek zniknie, po prostu dołącz google sql ; są to diagramy Venna różnych typów sprzężeń.
Zimano

Odpowiedzi:

190

LEFT OUTER JOIN zwróci wszystkie rekordy z tabeli LEFT połączone z tabelą RIGHT, jeśli to możliwe.

Jeśli jednak istnieją dopasowania, nadal zwróci wszystkie pasujące wiersze, dlatego jeden wiersz w LEWEJ, który pasuje do dwóch wierszy w PRAWO, zwróci jako dwa WIERSZE, tak jak INNER JOIN.

EDYCJA: W odpowiedzi na Twoją zmianę właśnie przyjrzałem się Twojemu zapytaniu i wygląda na to, że zwracasz tylko dane z LEWEJ tabeli. Dlatego, jeśli chcesz tylko danych z tabeli LEFT i chcesz, aby zwracany był tylko jeden wiersz dla każdego wiersza w tabeli LEFT, nie musisz w ogóle wykonywać JOIN i możesz po prostu wykonać polecenie SELECT bezpośrednio z tabeli LEFT.

Robin Day
źródło
1
Powodem dołączenia do prawego stołu było to, że dostałem tylko rekordy z lewej strony, gdzie był co najmniej jeden rekord w prawym stole, ale dziękuję bardzo za wyjaśnienie.
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

Wyniki:

1,null
2,2
2,2
3,null
4,null
Andrew Lewis
źródło
1
Tak proste, a jednocześnie tak potężne.
kiradotee
39

To nie jest niemożliwe. Liczba rekordów w lewej tabeli to minimalna liczba rekordów, które zwróci. Jeśli w prawej tabeli są dwa rekordy, które pasują do jednego rekordu w lewej tabeli, zwróci dwa rekordy.

HLGEM
źródło
12

W odpowiedzi na Twój postscript, to zależy od tego, co chcesz.

Otrzymujesz (możliwe) wiele wierszy dla każdego wiersza w lewej tabeli, ponieważ istnieje wiele dopasowań dla warunku sprzężenia. Jeśli chcesz, aby wszystkie wyniki miały taką samą liczbę wierszy, jak w lewej części zapytania, upewnij się, że warunki łączenia powodują dopasowanie 1 do 1.

Alternatywnie, w zależności od tego, czego naprawdę chcesz, możesz użyć funkcji agregujących (jeśli na przykład chcesz tylko ciąg z prawej części, możesz wygenerować kolumnę, która jest ciągiem rozdzielanym przecinkami z prawej strony wyników dla tego lewego wiersza.

Jeśli patrzysz tylko na 1 lub 2 kolumny ze sprzężenia zewnętrznego, możesz rozważyć użycie podzapytania skalarnego, ponieważ będziesz mieć zagwarantowany 1 wynik.

Chris Cameron-Mills
źródło
4
To dobra odpowiedź, ponieważ zawiera sugestie dotyczące zwracania tylko wierszy z lewej tabeli.
karns
9

Każdy rekord z lewej tabeli zostanie zwrócony tyle razy, ile pasujących rekordów znajduje się w prawej tabeli - co najmniej 1, ale z łatwością może być ich więcej niż 1.

Alex Martelli
źródło
8

LEFT OUTER JOIN podobnie jak INNER JOIN (zwykłe sprzężenie) zwróci tyle wyników dla każdego wiersza w lewej tabeli, ile dopasowań znajdzie w prawej tabeli. Stąd możesz mieć wiele wyników - aż do N x M, gdzie N to liczba wierszy w lewej tabeli, a M to liczba wierszy w prawej tabeli.

Minimalna liczba wyników jest zawsze gwarantowana w LEFT OUTER JOIN na co najmniej N.

topchef
źródło
1
Zacząłem myśleć, kiedy liczba rzędów jest równa N x M i jedyną realną sytuacją, która przychodzi mi na myśl, jest sytuacja, gdy N lub M jest równe 1. Zgadzasz się?
BartoszMiller
2
Nie, nie wiem. Nie powinieneś myśleć o warunku złączenia jako o kluczowym złączeniu równości. Może to być warunek dowolny, np. Zakresy dat, nierówności itp. Dwa skrajne przypadki: (a) N wierszy nie ma ani jednego dopasowania wśród M wierszy, wówczas lewe sprzężenie zewnętrzne daje N wierszy dopasowanych do wartości NULL. (b) każdy z N wierszy pasuje do wszystkich M wierszy, a wynik to zestaw N x M wierszy.
topchef
1
Masz rację, myślałem o złączeniach tylko w kategoriach kluczowej równości. Podoba mi się twój przykład z „przypadku b”. Uważam, że „każdy z N wierszy pasuje do wszystkich M wierszy” to ogólna recepta na zwrócenie N x M wierszy, co jest raczej niemożliwe do wyobrażenia, gdy myślimy tylko o równości kluczy.
BartoszMiller
7

Czy może to być relacja jeden do wielu między lewym i prawym stołem?

Ken Burkhardt
źródło
6

Zwróć uwagę, jeśli masz klauzulę where w tabeli "prawej strony" zapytania zawierającej lewe sprzężenie zewnętrzne ... W przypadku, gdy nie masz rekordu po prawej stronie spełniającego klauzulę where, wtedy odpowiadający rekord "lewej strony" 'tabela nie pojawi się w wyniku zapytania ....

Serge
źródło
1
Następnie należy dodać warunek do klauzuli ON odpowiedniego LEFT OUTER JOIN.
Mik
6

Jeśli potrzebujesz tylko jednego rzędu z prawej strony

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

Lub tylko

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
źródło
1
Ponieważ nie dostarczyłeś DDL i DML, nie testowałem. W każdym razie myślę, że ISTNIEJE jest tym, czego chcesz. Spróbuj tego: 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 OUT.Susp_Visits.SiteID) AS rn FROM SUSits LEFT_VV JOIN DATA.Dim_Member ON SUSP.Susp_Visits.MemID = DATA.Dim_Member.MembershipNum) AS t WHERE rn = 1
AK
2

Wygląda na to, że w tabeli DATA.Dim_Member znajduje się wiele wierszy na wiersz SUSP.Susp_Visits.

bdukes
źródło
2

jeśli wiele (x) wierszy w Dim_Member jest powiązanych z jednym wierszem w Susp_Visits, w zestawie wyników będzie x wierszy.

Manu
źródło