Chcę wykonać Full Outer Join w MySQL. czy to możliwe? Czy MySQL obsługuje pełne przyłączenie zewnętrzne?
sql
mysql
join
outer-join
full-outer-join
Spencer
źródło
źródło
Odpowiedzi:
Nie masz PEŁNYCH ŁĄCZEŃ na MySQL, ale z pewnością możesz je emulować .
W przypadku kodu PRÓBKI przepisanego z tego pytania SO masz:
z dwiema tabelami t1, t2:
Powyższe zapytanie działa w szczególnych przypadkach, w których operacja FULL OUTER JOIN nie wygenerowałaby żadnych duplikatów wierszy. Powyższe zapytanie zależy od
UNION
ustawionego operatora, aby usunąć zduplikowane wiersze wprowadzone przez wzorzec zapytania. Możemy uniknąć wprowadzania zduplikowanych wierszy przez stosując anty-przyłączyć wzorzec dla drugiego zapytania, a następnie użyć zestawu operator UNION ALL, aby połączyć dwa sety. W bardziej ogólnym przypadku, gdy PEŁNE DOŁĄCZENIE DO ZEWNĄTRZ zwróci zduplikowane wiersze, możemy to zrobić:źródło
(SELECT ... FROM tbl1 LEFT JOIN tbl2 ...) UNION ALL (SELECT ... FROM tbl1 RIGHT JOIN tbl2 ... WHERE tbl1.col IS NULL)
t1
it2
, zapytanie w tej odpowiedzi nie zwraca zestaw wyników, które emuluje FULL OUTER JOIN. Ale w bardziej ogólnym przypadku, na przykład, lista SELECT nie zawiera wystarczającej liczby kolumn / wyrażeń, aby zwracane wiersze były unikalne, wówczas ten wzorzec zapytania jest niewystarczający do odtworzenia zestawu, który zostałby wygenerowany przezFULL OUTER JOIN
. Aby uzyskać bardziej wierną emulację, potrzebowalibyśmyUNION ALL
operatora set, a jedno z zapytań wymagałoby wzorca zapobiegającego łączeniu . Komentarz Pavle Lekic (powyżej) podaje prawidłowy wzorzec zapytania.Odpowiedź, którą udzielił Pablo Santa Cruz, jest poprawna; jednak w przypadku, gdy ktoś natknie się na tę stronę i chce więcej wyjaśnień, oto szczegółowy podział.
Przykładowe tabele
Załóżmy, że mamy następujące tabele:
Wewnętrzne połączenia
Połączenie wewnętrzne, takie jak to:
Otrzymalibyśmy od nas tylko te rekordy, które pojawiają się w obu tabelach:
Połączenia wewnętrzne nie mają kierunku (jak w lewo lub w prawo), ponieważ są wyraźnie dwukierunkowe - wymagamy dopasowania po obu stronach.
Połączenia zewnętrzne
Z drugiej strony sprzężenia zewnętrzne służą do wyszukiwania rekordów, które mogą nie mieć dopasowania w drugiej tabeli. W związku z tym musisz określić, która strona sprzężenia może mieć brakujący rekord.
LEFT JOIN
iRIGHT JOIN
są skrótami dlaLEFT OUTER JOIN
iRIGHT OUTER JOIN
; Wykorzystam ich pełne nazwy poniżej, aby wzmocnić koncepcję złączeń zewnętrznych vs. złączeń wewnętrznych.Lewy zewnętrzny łącznik
Lewe połączenie zewnętrzne, takie jak to:
... dostarczyłby nam wszystkie rekordy z lewej tabeli niezależnie od tego, czy pasują do prawej tabeli, jak poniżej:
Right Outer Join
Prawe połączenie zewnętrzne, takie jak to:
... dostarczyłby nam wszystkie rekordy z prawej tabeli, niezależnie od tego, czy pasują do lewej tabeli, jak poniżej:
Pełne połączenie zewnętrzne
Pełne sprzężenie zewnętrzne dałoby nam wszystkie rekordy z obu tabel, bez względu na to, czy pasują one do drugiej tabeli, z wartościami NULL po obu stronach, w których nie ma zgodności. Wynik wyglądałby tak:
Jednak, jak zauważył Pablo Santa Cruz, MySQL tego nie obsługuje. Możemy to naśladować, wykonując UNION lewego i prawego łączenia, w następujący sposób:
Możesz pomyśleć o tym,
UNION
co oznacza „uruchom oba te zapytania, a następnie ułóż wyniki jeden na drugim”; niektóre wiersze będą pochodzić z pierwszego zapytania, a niektóre z drugiego.Należy zauważyć, że a
UNION
w MySQL wyeliminuje dokładne duplikaty: Tim pojawiłby się w obu zapytaniach tutaj, ale wynikUNION
jedynego wypisuje go raz. Mój kolega guru z bazy danych uważa, że nie należy polegać na tym zachowaniu. Aby być bardziej precyzyjnym, możemy dodaćWHERE
klauzulę do drugiego zapytania:Z drugiej strony, jeśli chcieliśmy zobaczyć duplikaty z jakiegoś powodu, można użyć
UNION ALL
.źródło
FULL OUTER JOIN
. Nie ma nic złego w robieniu zapytań w ten sposób i użyciu UNION do usuwania tych duplikatów. Ale aby naprawdę powielićFULL OUTER JOIN
, potrzebujemy jednego z zapytań, aby być antywirusowym.UNION
operacja usunie te duplikaty; ale usuwa również WSZYSTKIE zduplikowane wiersze, w tym zduplikowane wiersze, które byłyby zwrócone przez PEŁNE ZŁĄCZE ZEWNĘTRZNE. Aby emulowaća FULL JOIN b
, prawidłowy wzór to(a LEFT JOIN b) UNION ALL (b ANTI JOIN a)
.Użycie
union
zapytania usunie duplikaty, a to różni się od zachowania,full outer join
które nigdy nie usuwa duplikatów:Jest to oczekiwany wynik
full outer join
:Jest to wynikiem zastosowania
left
orazright Join
zunion
:[SQL Fiddle]
Moje sugerowane zapytanie to:
Wynik powyższego zapytania, który jest taki sam jak oczekiwany wynik:
[SQL Fiddle]
Postanowiłem dodać kolejne rozwiązanie, które pochodzi z
full outer join
wizualizacji i matematyki, nie jest lepsze niż powyższe, ale bardziej czytelne:[SQL Fiddle]
źródło
FULL OUTER JOIN
. Ten post na blogu również to dobrze wyjaśnia - cytując z metody 2: „To poprawnie obsługuje zduplikowane wiersze i nie zawiera niczego, czego nie powinno. Konieczne jest użycie UNION ALL zamiast zwykłego UNION, co wyeliminowałoby duplikaty, które chcę zachowaj. Może to być znacznie bardziej wydajne w przypadku dużych zestawów wyników, ponieważ nie ma potrzeby sortowania i usuwania duplikatów ”.MySql nie ma składni FULL-OUTER-JOIN. Musisz naśladować, wykonując LEWE DOŁĄCZ i PRAWE DOŁĄCZ w następujący sposób -
Ale MySql nie ma również PRAWEJ składni. Według MySql's zewnętrznym uproszczeniem łączenia , prawe złączenie jest konwertowane na równoważne lewe łączenie, przełączając t1 i t2 w klauzuli
FROM
iON
w zapytaniu. Tak więc MySql Query Optimizer tłumaczy oryginalne zapytanie na następujące -Teraz pisanie oryginalnego zapytania nie jest szkodliwe, ale powiedz, jeśli masz predykaty takie jak klauzula WHERE, która jest predykatem przed dołączeniem lub predykatem AND w
ON
klauzuli, która jestpredykatem podczas łączenia , może chcieć spojrzeć na diabła; co jest szczegółowo.Optymalizator zapytań MySql rutynowo sprawdza predykaty, jeśli są odrzucane z null . Teraz, jeśli wykonałeś PRAWIDŁOWE DOŁĄCZENIE, ale z GDZIE predykatem w kolumnie od t1, możesz być narażony na ryzyko wystąpienia scenariusza z zerową wartością odrzuconą .
Na przykład następujące zapytanie -
zostanie przetłumaczone na następujące przez Optymalizator zapytań-
Kolejność tabel zmieniła się, ale predykat jest nadal stosowany do t1, ale t1 znajduje się teraz w klauzuli „ON”. Jeśli t1.col1 jest zdefiniowany jako
NOT NULL
kolumna, to zapytanie zostanie odrzucone z .Każde sprzężenie zewnętrzne (lewy, prawy, pełny), które jest odrzucane z null, jest konwertowane na łączenie wewnętrzne przez MySql.
Tak więc wyniki, których możesz się spodziewać, mogą być całkowicie różne od tego, co zwraca MySql. Możesz pomyśleć, że to błąd w RIGHT JOIN MySql, ale to nie w porządku. Właśnie tak działa optymalizator zapytań MySql. Więc odpowiedzialny za programista musi zwracać uwagę na te niuanse podczas konstruowania zapytania.
źródło
W SQLite powinieneś to zrobić:
źródło
Żadna z powyższych odpowiedzi nie jest w rzeczywistości poprawna, ponieważ nie są zgodne z semantyką, gdy występują zduplikowane wartości.
W przypadku zapytania takiego jak (z tego duplikatu ):
Prawidłowy odpowiednik to:
Jeśli potrzebujesz, aby działało to z
NULL
wartościami (które mogą być również konieczne), użyj zamiast tegoNULL
operatora porównywania -safe .<=>
=
źródło
FULL OUTER JOIN
każdym razem, gdyname
kolumna jest pusta.union all
Zapytanie z anty-przyłączenia wzór powinien odtworzenia sprzężenia zewnętrznego zachowania prawidłowo, a który to roztwór jest bardziej odpowiedni w zależności od kontekstu i ograniczeń, które są aktywne w tabelach.union all
, ale ta odpowiedź pomija wzór zapobiegający łączeniu w pierwszym lub drugim zapytaniu, które zachowa istniejące duplikaty, ale uniemożliwi dodanie nowych. W zależności od kontekstu inne rozwiązania (takie jak to) mogą być bardziej odpowiednie.Zmodyfikowano zapytanie shA.t dla większej przejrzystości:
źródło
Możesz wykonać następujące czynności:
źródło
co powiedziałeś o rozwiązaniu Cross Join ?
źródło
select (select count(*) from t1) * (select count(*) from t2))
wierszami w zestawie wyników.źródło
Jest to również możliwe, ale musisz zaznaczyć te same nazwy pól w select.
źródło
Naprawiam odpowiedź i prace obejmują wszystkie wiersze (na podstawie odpowiedzi Pavle Lekic)
źródło
tablea
, w których nie ma dopasowaniatableb
i na odwrót. PróbujeszUNION ALL
, co zadziałałoby tylko wtedy, gdy te dwie tabele mają równo uporządkowane kolumny, co nie jest gwarantowane.Odpowiedź:
Można odtworzyć w następujący sposób:
Zastosowanie odpowiedzi UNION lub UNION ALL nie obejmuje przypadku na brzegu, w którym tabele podstawowe mają zduplikowane wpisy.
Wyjaśnienie:
Istnieje przypadek skrajny, którego UNION lub UNION ALL nie są w stanie objąć. Nie możemy przetestować tego na mysql, ponieważ nie obsługuje on FULL OUTER JOIN, ale możemy to zilustrować w bazie danych, która go obsługuje:
Rozwiązanie UNION:
Podaje niepoprawną odpowiedź:
Rozwiązanie UNION ALL:
Jest również niepoprawny.
Podczas gdy to zapytanie:
Daje następujące:
Kolejność jest inna, ale poza tym odpowiada poprawnej odpowiedzi.
źródło
UNION ALL
rozwiązanie. Przedstawia również rozwiązanie, wUNION
którym wolniej działałoby na dużych tabelach źródłowych z powodu wymaganego usuwania duplikacji. Wreszcie nie skompiluje się, ponieważ poleid
nie istnieje w podzapytaniutmp
.UNION ALL
Rozwiązanie:… jest również niepoprawne”. Prezentowany kod pomija wykluczenie przecięcia z funkcji right-join (where t1.id1 is null
), którą należy podać w plikuUNION ALL
. Oznacza to, że Twoje rozwiązanie przebija wszystkie pozostałe, tylko wtedy, gdy jedno z tych innych rozwiązań zostanie nieprawidłowo zaimplementowane. Na „uroczość”, punkt. To było za darmo, przepraszam.Średnia SQL mówi
full join on
toinner join on
wierszeunion all
niedopasowane wiersze lewej tabeli udzielonych przez nullunion all
prawy wiersze tabeli przedłużony o wartości null. Tzn.inner join on
Rzędy wunion all
rzędach,left join on
ale nie winner join on
union all
rzędach,right join on
ale nieinner join on
.Tzn.
left join on
Wierszyunion all
right join on
nie mainner join on
. Lub jeśli wiesz, że twójinner join on
wynik nie może mieć wartości null w konkretnej prawej kolumnie tabeli, wówczas „right join on
wiersze nie winner join on
” to wierszeright join on
zon
warunkiem rozszerzonym przezand
tę kolumnęis null
.Tj. Podobnie
right join on
union all
odpowiednieleft join on
rzędy.Od Jaka jest różnica między „INNER JOIN” a „OUTER JOIN”? :
źródło