Przykład z tabel A i B:
A (parent) B (child)
============ =============
id | name pid | name
------------ -------------
1 | Alex 1 | Kate
2 | Bill 1 | Lia
3 | Cath 3 | Mary
4 | Dale NULL | Pan
5 | Evan
Jeśli chcesz odnaleźć rodziców i ich dzieci, to zrobić INNER JOIN
:
SELECT id, parent.name AS parent
, pid, child.name AS child
FROM
parent INNER JOIN child
ON parent.id = child.pid
Powoduje to, że każdy mecz parent
z lewej tabeli i pid
z drugiej tabeli będzie wyświetlane jako wiersz w wyniku:
+----+--------+------+-------+
| id | parent | pid | child |
+----+--------+------+-------+
| 1 | Alex | 1 | Kate |
| 1 | Alex | 1 | Lia |
| 3 | Cath | 3 | Mary |
+----+--------+------+-------+
Teraz powyższe nie pokazać rodziców bez dzieci (ponieważ ich identyfikatory nie mają odpowiednika w identyfikatory dziecka, więc co zrobić? Zamiast tego robisz zewnętrzne sprzężenie. Istnieją trzy rodzaje sprzężeń zewnętrznych, lewe, prawe i pełne sprzężenie zewnętrzne. Musimy lewa, jak chcemy „ekstra” wiersze z lewej tabeli (rodzic):
SELECT id, parent.name AS parent
, pid, child.name AS child
FROM
parent LEFT JOIN child
ON parent.id = child.pid
Powoduje to, że oprócz poprzednich meczów, wszyscy rodzice, że nie mają meczu (czytaj: nie mają kid) przedstawiono też:
+----+--------+------+-------+
| id | parent | pid | child |
+----+--------+------+-------+
| 1 | Alex | 1 | Kate |
| 1 | Alex | 1 | Lia |
| 3 | Cath | 3 | Mary |
| 2 | Bill | NULL | NULL |
| 4 | Dale | NULL | NULL |
| 5 | Evan | NULL | NULL |
+----+--------+------+-------+
Skąd wszystkich tych NULL
pochodzi? Cóż, MySQL (lub jakikolwiek inny RDBMS, którego możesz użyć) nie będzie wiedział, co tam umieścić, ponieważ rodzice nie mają dopasowania (dziecko), więc nie ma pid
ani child.name
, aby dopasować się do tych rodziców. W związku z tym umieszcza tę wyjątkową wartość o nazwie NULL
.
Chodzi mi o to, że te NULLs
zostały utworzone (w zestawie wyników) podczas LEFT OUTER JOIN
.
Tak więc, jeśli chcemy pokazać tylko rodzicom, że nie masz chłopaka, możemy dodać WHERE child.pid IS NULL
do powyższego LEFT JOIN
. Klauzula WHERE
jest oceniana (sprawdzana) po wykonaniu JOIN
.Tak, to wynika z powyższego wyniku, że tylko trzy ostatnie wiersze gdzie pid
jest NULL zostaną pokazane:
SELECT id, parent.name AS parent
, pid, child.name AS child
FROM
parent LEFT JOIN child
ON parent.id = child.pid
WHERE child.pid IS NULL
Wynik:
+----+--------+------+-------+
| id | parent | pid | child |
+----+--------+------+-------+
| 2 | Bill | NULL | NULL |
| 4 | Dale | NULL | NULL |
| 5 | Evan | NULL | NULL |
+----+--------+------+-------+
Teraz, co się dzieje, gdy poruszamy się, że IS NULL
sprawdź od klauzuli WHERE
do dołączenia ON
?
SELECT id, parent.name AS parent
, pid, child.name AS child
FROM
parent LEFT JOIN child
ON parent.id = child.pid
AND child.pid IS NULL
W tym przypadku baza danych próbuje znaleźć wiersze z dwóch tabel, które spełniają te warunki. To znaczy, wiersze, w których są , i . Ale może znaleźć żadnego takiego dopasowania ponieważ żadna child.pid
może być równa czemuś (1, 2, 3, 4 lub 5) i mieć wartość NULL w tym samym czasie!
więc warunek:
ON parent.id = child.pid
AND child.pid IS NULL
odpowiada:
ON 1 = 0
która zawsze False
.
Dlaczego więc zwraca WSZYSTKIE wiersze z lewej tabeli? Bo to LEFT DOŁĄCZ! i lewej dołącza powrócić wiersze, które pasują (brak w tym przypadku) a także rzędy od lewej tabeli, które nie pasują czek (wszystko w tym przypadku):
+----+--------+------+-------+
| id | parent | pid | child |
+----+--------+------+-------+
| 1 | Alex | NULL | NULL |
| 2 | Bill | NULL | NULL |
| 3 | Cath | NULL | NULL |
| 4 | Dale | NULL | NULL |
| 5 | Evan | NULL | NULL |
+----+--------+------+-------+
Mam nadzieję, że powyższe wyjaśnienie jest jasne.
Sidenote (nie związane bezpośrednio z pytaniem): Dlaczego na ziemi nie Pan
ma pokazać się w żaden z naszych JOIN? Ponieważ jego pid
jest NULL
i NULL w (nie powszechnej) logice SQL nie jest równy czemukolwiek, więc nie może się równać z żadnym z nadrzędnych identyfikatorów (które są 1,2,3,4 i 5). Nawet jeśli był tam NULL, nadal nie pasowałoby, ponieważ NULL
nie jest równe, nawet samo NULL
(to bardzo dziwna logika!). Dlatego używamy czeku specjalnego IS NULL
, a nie testu = NULL
.
Czy pojawi się Pan
, jeśli wykonamy RIGHT JOIN
? Tak, to będzie! Ponieważ RIGHT JOIN pokaże wszystkie wyniki spełniające (pierwszy INNER JOIN my) oraz wszystkie wiersze z tabeli rację, że nie pasują do siebie (co w naszym przypadku jest tylko jedna, (NULL, 'Pan')
rząd.
SELECT id, parent.name AS parent
, pid, child.name AS child
FROM
parent RIGHT JOIN child
ON parent.id = child.pid
Rezultat :
+------+--------+------+-------+
| id | parent | pid | child |
+---------------+------+-------+
| 1 | Alex | 1 | Kate |
| 1 | Alex | 1 | Lia |
| 3 | Cath | 3 | Mary |
| NULL | NULL | NULL | Pan |
+------+--------+------+-------+
Niestety, MySQL nie posiada FULL JOIN
.Można spróbować w innym RDBMSs, i pokaże:
+------+--------+------+-------+
| id | parent | pid | child |
+------+--------+------+-------+
| 1 | Alex | 1 | Kate |
| 1 | Alex | 1 | Lia |
| 3 | Cath | 3 | Mary |
| 2 | Bill | NULL | NULL |
| 4 | Dale | NULL | NULL |
| 5 | Evan | NULL | NULL |
| NULL | NULL | NULL | Pan |
+------+--------+------+-------+
Możesz sfałszować "FULL JOIN" w MySQL, biorąc związek pomiędzy 'LEFT JOIN' i' RIGHT JOIN', gdzie id to 'NULL'. Ma to ograniczenia - na przykład nie można aktualizować ani usuwać - i prawdopodobnie jest to większy problem niż jest to warte. – Duncan