sql >> Database >  >> RDS >> Oracle

IS NULL of IS NOT NULL gebruiken op join-voorwaarden - Theorievraag

Voorbeeld met tabellen A en 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  

Als je ouders en hun kinderen wilt vinden, doe je een INNER JOIN :

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

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

Het resultaat is dat elke match van een parent 's id uit de linkertabel en een child 's pid uit de tweede tabel wordt weergegeven als een rij in het resultaat:

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

Nu worden in het bovenstaande geen ouders zonder kinderen weergegeven (omdat hun id's geen overeenkomst hebben in de id's van het kind, dus wat doe je? In plaats daarvan doe je een outer join. Er zijn drie soorten outer joins, de linker, de rechter en de volledige outer join. We hebben de linker nodig omdat we de "extra" rijen van de linkertabel (ouder) willen:

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

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

Het resultaat is dat naast eerdere matches, ook alle ouders die geen match hebben (lees:geen kind hebben) getoond worden:

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

Waar zijn al die NULL Komt van? Welnu, MySQL (of een ander RDBMS dat u misschien gebruikt) zal niet weten wat ze daar moeten plaatsen, aangezien deze ouders geen match hebben (kid), dus er is geen pid noch child.name passen bij die ouders. Dus, het plaatst deze speciale niet-waarde genaamd NULL .

Mijn punt is dat deze NULLs worden gemaakt (in de resultatenset) tijdens de LEFT OUTER JOIN .

Dus als we alleen de ouders willen tonen die GEEN kind hebben, kunnen we een WHERE child.pid IS NULL toevoegen naar de LEFT JOIN boven. De WHERE clausule wordt geëvalueerd (aangevinkt) na de JOIN is klaar. Het is dus duidelijk uit het bovenstaande resultaat dat alleen de laatste drie rijen waar de pid is NULL wordt weergegeven:

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

Resultaat:

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

Wat gebeurt er als we die IS NULL verplaatsen? controleer vanaf de WHERE naar de deelname ON clausule?

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

In dit geval probeert de database rijen te vinden uit de twee tabellen die aan deze voorwaarden voldoen. Dat wil zeggen, rijen waar parent.id = child.pid EN child.pid IN NULL . Maar het kan zo'n overeenkomst niet vinden omdat geen child.pid kan gelijk zijn aan iets (1, 2, 3, 4 of 5) en tegelijkertijd NULL zijn!

Dus de voorwaarde:

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

is gelijk aan:

ON   1 = 0

wat altijd False . is .

Dus, waarom retourneert het ALLE rijen uit de linkertabel? Omdat het een LEFT JOIN is! En left joins retourneren rijen die overeenkomen (geen in dit geval) en ook rijen uit de linkertabel die niet overeenkomen het vinkje (allemaal in dit geval ):

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

Ik hoop dat de bovenstaande uitleg duidelijk is.

Sidenote (niet direct gerelateerd aan uw vraag):Waarom in hemelsnaam niet Pan verschijnen in geen van onze JOINs? Omdat zijn pid is NULL en NULL in de (niet gebruikelijke) logica van SQL is nergens gelijk aan, dus het kan niet overeenkomen met een van de bovenliggende id's (die 1,2,3,4 en 5 zijn). Zelfs als er een NULL was, zou deze nog steeds niet overeenkomen omdat NULL is nergens gelijk aan, zelfs niet NULL zelf (het is inderdaad een heel vreemde logica!). Daarom gebruiken we de speciale controle IS NULL en niet een = NULL controleren.

Dus, zal Pan verschijnen als we een RIGHT JOIN doen ? Ja het zal! Omdat een RIGHT JOIN alle resultaten toont die overeenkomen (de eerste INNER JOIN die we deden) plus alle rijen uit de RIGHT-tabel die niet overeenkomen (wat in ons geval één is, de (NULL, 'Pan') rij.

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

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

Resultaat:

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

Helaas heeft MySQL geen FULL JOIN . Je kunt het in andere RDBMS'en proberen, en het zal tonen:

+------+--------+------+-------+
|  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. Selecteer TOP X (of onderste) procent voor numerieke waarden in MySQL

  2. Verbindingsbeheer in PostgreSQL:een gids

  3. Hoe maak je een index voor elementen van een array in PostgreSQL?

  4. WordPress installeren met WP-CLI