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


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.


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

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.


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.


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.


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.


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


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 ....


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
)

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.


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.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.