Пример с таблици A и 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
Ако искате да намерите родители и техните деца, направете INNER JOIN
:
SELECT id, parent.name AS parent
, pid, child.name AS child
FROM
parent INNER JOIN child
ON parent.id = child.pid
Резултатът е, че всяко съвпадение на родител
id
на от лявата таблица и дете
pid
от втората таблица ще се покаже като ред в резултата:
+----+--------+------+-------+
| id | parent | pid | child |
+----+--------+------+-------+
| 1 | Alex | 1 | Kate |
| 1 | Alex | 1 | Lia |
| 3 | Cath | 3 | Mary |
+----+--------+------+-------+
Сега горното не показва родители без деца (тъй като техните идентификационни номера нямат съвпадение в идентификаторите на детето, така че какво правите? Вместо това правите външно присъединяване. Има три вида външни свързвания, ляво, дясно и пълното външно присъединяване. Трябва ни лявото, тъй като искаме "допълнителните" редове от лявата таблица (родител):
SELECT id, parent.name AS parent
, pid, child.name AS child
FROM
parent LEFT JOIN child
ON parent.id = child.pid
Резултатът е, че освен предишни мачове, всички родители, които нямат съвпадение (прочетете:нямат дете) също се показват:
+----+--------+------+-------+
| 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
идвам от? Е, MySQL (или всяка друга RDBMS, която може да използвате) няма да знае какво да постави там, тъй като тези родители нямат съвпадение (дете), така че няма pid
нито child.name
да съвпадат с тези родители. И така, той поставя тази специална нестойност, наречена NULL
.
Моето мнение е, че тези NULL
се създават (в резултатния набор) по време на LEFT OUTER JOIN
.
Така че, ако искаме да покажем само родителите, които НЯМАТ дете, можем да добавим WHERE child.pid IS NULL
към LEFT JOIN
по-горе. КЪДЕ
Клаузата се оценява (проверява) след JOIN
готово е. Така че от горния резултат е ясно, че само последните три реда, където pid
е NULL ще се покаже:
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
Резултат:
+----+--------+------+-------+
| id | parent | pid | child |
+----+--------+------+-------+
| 2 | Bill | NULL | NULL |
| 4 | Dale | NULL | NULL |
| 5 | Evan | NULL | NULL |
+----+--------+------+-------+
Сега, какво ще стане, ако преместим това IS NULL
проверете от КЪДЕ
към присъединителния 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
В този случай базата данни се опитва да намери редове от двете таблици, които отговарят на тези условия. Тоест редове, където parent.id =child.pid
И child.pid В NULL
. Но може да намери няма такова съвпадение защото няма child.pid
може да бъде равно на нещо (1, 2, 3, 4 или 5) и да бъде NULL в същото време!
И така, условието:
ON parent.id = child.pid
AND child.pid IS NULL
е еквивалентен на:
ON 1 = 0
което винаги е False
.
И така, защо връща ВСИЧКИ редове от лявата таблица? Защото е ЛЯВО ПРИСЪЕДИНЯВАНЕ! И левите съединения връщат редове, които съвпадат (в този случай няма) а също иредове от лявата таблица, които не съвпадати проверката (всички в този случай ):
+----+--------+------+-------+
| id | parent | pid | child |
+----+--------+------+-------+
| 1 | Alex | NULL | NULL |
| 2 | Bill | NULL | NULL |
| 3 | Cath | NULL | NULL |
| 4 | Dale | NULL | NULL |
| 5 | Evan | NULL | NULL |
+----+--------+------+-------+
Надявам се, че горното обяснение е ясно.
Странична бележка (не е пряко свързана с вашия въпрос):Защо, за бога, не Pan
не се показват в нито едно от нашите JOIN? Защото неговият pid
е NULL
и NULL в (не обичайната) логика на SQL не е равно на нищо, така че не може да съвпадне с нито един от родителските идентификатори (които са 1,2,3,4 и 5). Дори и да имаше NULL там, то пак нямаше да съвпадне, защото NULL
не е равно на нищо, дори не на NULL
(това е много странна логика, наистина!). Ето защо използваме специалната проверка IS NULL
а не =NULL
проверете.
Така че, ще Панорамиране
се появяват, ако направим RIGHT JOIN
? Да, ще стане! Тъй като RIGHT JOIN ще покаже всички резултати, които съвпадат (първото INNER JOIN, което направихме) плюс всички редове от ДЯСНАТА таблица, които не съвпадат (което в нашия случай е един, (NULL, 'Pan')код> ред.
SELECT id, parent.name AS parent
, pid, child.name AS child
FROM
parent RIGHT JOIN child
ON parent.id = child.pid
Резултат:
+------+--------+------+-------+
| id | parent | pid | child |
+---------------+------+-------+
| 1 | Alex | 1 | Kate |
| 1 | Alex | 1 | Lia |
| 3 | Cath | 3 | Mary |
| NULL | NULL | NULL | Pan |
+------+--------+------+-------+
За съжаление MySQL няма FULL JOIN
. Можете да го опитате в други RDBMS и той ще покаже:
+------+--------+------+-------+
| 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 |
+------+--------+------+-------+