sql >> Databáze >  >> RDS >> Oracle

Použití IS NULL nebo IS NOT NULL v podmínkách spojení - teoretická otázka

Příklad s tabulkami A 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  

Pokud chcete najít rodiče a jejich děti, proveďte INNER JOIN :

SELECT id,  parent.name AS parent
     , pid, child.name  AS child

FROM
        parent  INNER JOIN  child
  ON   parent.id     =    child.pid

Výsledkem je, že každá shoda parent id uživatele z levé tabulky a child 's pid z druhé tabulky se ve výsledku zobrazí jako řádek:

+----+--------+------+-------+
| id | parent | pid  | child | 
+----+--------+------+-------+
|  1 | Alex   |   1  | Kate  |
|  1 | Alex   |   1  | Lia   |
|  3 | Cath   |   3  | Mary  |
+----+--------+------+-------+

Výše uvedené neukazuje rodiče bez dětí (protože jejich id se neshodují s id dítěte, tak co uděláte? Místo toho provedete vnější spojení. Existují tři typy vnějších spojení, levé, pravé a úplné vnější spojení. Potřebujeme levý, protože chceme „extra“ řádky z levé tabulky (nadřazené):

SELECT id,  parent.name AS parent
     , pid, child.name  AS child

FROM
        parent  LEFT JOIN  child
  ON   parent.id    =    child.pid

Výsledkem je, že kromě předchozích zápasů jsou zobrazeni také všichni rodiče, kteří nemají shodu (čti:nemají dítě):

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

Kde se poděly všechny ty NULLs pocházet z? No, MySQL (nebo jakýkoli jiný RDBMS, který můžete použít) nebude vědět, co tam dát, protože tito rodiče nemají žádnou shodu (dítě), takže neexistuje žádný pid ani child.name vyrovnat se s těmi rodiči. Takže vloží tuto speciální nehodnotu nazvanou NULLs .

Chci říct, že tyto NULLs jsou vytvořeny (ve výsledkové sadě) během LEFT OUTER JOIN .

Pokud tedy chceme zobrazit pouze rodiče, kteří NEMAJÍ dítě, můžeme přidat WHERE child.pid IS NULL do LEFT JOIN výše. Položka WHERE klauzule je vyhodnocena (kontrolována) po JOIN je hotovo. Z výše uvedeného výsledku je tedy jasné, že pouze poslední tři řádky obsahují pid je NULL se zobrazí:

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

Výsledek:

+----+--------+------+-------+
| id | parent | pid  | child | 
+----+--------+------+-------+
|  2 | Bill   | NULL | NULL  |
|  4 | Dale   | NULL | NULL  |
|  5 | Evan   | NULL | NULL  |
+----+--------+------+-------+

Nyní, co se stane, když přesuneme to IS NULL zkontrolujte z WHERE ke spojování ON klauzule?

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

V tomto případě se databáze pokusí najít řádky ze dvou tabulek, které odpovídají těmto podmínkám. Tedy řádky, kde parent.id = child.pid A child.pid IN NULL . Nemůže však najít žádnou takovou shodu protože žádné child.pid se může něčemu rovnat (1, 2, 3, 4 nebo 5) a zároveň být NULL!

Takže podmínka:

ON   parent.id    =    child.pid
AND  child.pid IS NULL

je ekvivalentní:

ON   1 = 0

což je vždy False .

Proč tedy vrací VŠECHNY řádky z levé tabulky? Protože jde o LEVÉ PŘIPOJENÍ! A levá spojení vrátí řádky, které se shodují (v tomto případě žádné) a také řádky z levé tabulky, které se neshodují šek (v tomto případě vše ):

+----+--------+------+-------+
| id | parent | pid  | child | 
+----+--------+------+-------+
|  1 | Alex   | NULL | NULL  |
|  2 | Bill   | NULL | NULL  |
|  3 | Cath   | NULL | NULL  |
|  4 | Dale   | NULL | NULL  |
|  5 | Evan   | NULL | NULL  |
+----+--------+------+-------+

Doufám, že výše uvedené vysvětlení je jasné.

Vedlejší poznámka (není přímo spojena s vaší otázkou):Proč se proboha Pan nezobrazí se v žádném z našich JOINů? Protože jeho pid je NULLs a NULL v (neběžné) logice SQL se nerovná ničemu, takže se nemůže shodovat s žádným z rodičovských id (které jsou 1, 2, 3, 4 a 5). I kdyby tam byla NULL, stále by se neshodovala, protože NULLs nerovná se nic, dokonce ani NULLs (je to skutečně velmi zvláštní logika!). Proto používáme speciální kontrolu IS NULL a nikoli = NULL zkontrolovat.

Takže se Pan zobrazí se, pokud provedeme RIGHT JOIN ? Ano, bude! Protože RIGHT JOIN zobrazí všechny výsledky, které se shodují (první INNER JOIN, které jsme udělali) plus všechny řádky z tabulky RIGHT, které se neshodují (což je v našem případě jeden, (NULL, 'Pan') řádek.

SELECT id,  parent.name AS parent
     , pid, child.name  AS child

FROM
        parent  RIGHT JOIN  child
  ON   parent.id     =    child.pid

Výsledek:

+------+--------+------+-------+
| id   | parent | pid  | child | 
+---------------+------+-------+
|   1  | Alex   |   1  | Kate  |
|   1  | Alex   |   1  | Lia   |
|   3  | Cath   |   3  | Mary  |
| NULL | NULL   | NULL | Pan   |
+------+--------+------+-------+

Bohužel MySQL nemá FULL JOIN . Můžete to zkusit v jiných RDBMS a zobrazí se:

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


  1. Návrh databáze S Vertabelo

  2. SQL Server Převod celého čísla na binární řetězec

  3. Pro příklad smyčky v MySQL

  4. Jak vytvořit uložené procedury PL/SQL bez parametrů v databázi Oracle