sql >> Databasteknik >  >> RDS >> Oracle

Att använda IS NULL eller IS NOT NULL på anslutningsvillkor - Teorifråga

Exempel med tabellerna A och 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  

Om du vill hitta föräldrar och deras barn gör du en INNER JOIN :

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

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

Resultatet är att varje matchning av en förälder s id från den vänstra tabellen och en underordnad s pid från den andra tabellen visas som en rad i resultatet:

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

Nu visar ovanstående inte föräldrar utan barn (eftersom deras id inte har en matchning i barnets id, så vad gör du? Du gör en yttre koppling istället. Det finns tre typer av yttre kopplingar, vänster, höger och den fullständiga yttre sammanfogningen. Vi behöver den vänstra eftersom vi vill ha de "extra" raderna från den vänstra tabellen (förälder):

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

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

Resultatet är att förutom tidigare matcher visas alla föräldrar som inte har en match (läs:inte har ett barn):

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

Var tog alla dessa NULL komma från? Tja, MySQL (eller något annat RDBMS du kan använda) kommer inte att veta vad de ska lägga där eftersom dessa föräldrar inte har någon match (barn), så det finns ingen pid inte heller barn.namn att matcha med dessa föräldrar. Så det sätter detta speciella icke-värde som kallas NULL .

Min poäng är att dessa NULLs skapas (i resultatuppsättningen) under LEFT OUTER JOIN .

Så om vi bara vill visa de föräldrar som INTE har ett barn, kan vi lägga till en WHERE child.pid IS NULL till LEFT JOIN ovan. VAR satsen utvärderas (markeras) efter JOIN är klart. Så det är tydligt från ovanstående resultat att endast de tre sista raderna innehåller pid är NULL kommer att visas:

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

Resultat:

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

Nu, vad händer om vi flyttar den ÄR NULL kontrollera från WHERE till den anslutande ON klausul?

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

I det här fallet försöker databasen hitta rader från de två tabellerna som matchar dessa villkor. Det vill säga rader där parent.id =child.pid OCH child.pid IN NULL . Men den kan hitta ingen sådan matchning eftersom ingen child.pid kan vara lika med något (1, 2, 3, 4 eller 5) och samtidigt vara NULL!

Så, villkoret:

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

motsvarar:

ON   1 = 0

som alltid är False .

Så varför returnerar den ALLA rader från den vänstra tabellen? Eftersom det är en VÄNSTERJOIN! Och vänsterkopplingar returnerar rader som matchar (inga i det här fallet) och även rader från den vänstra tabellen som inte matchar checken (alla i det här fallet ):

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

Jag hoppas att förklaringen ovan är tydlig.

Sidenote (inte direkt relaterat till din fråga):Varför i hela friden panoreras dyka upp i ingen av våra JOINs? Eftersom hans pid är NULL och NULL i (inte vanliga) logiken i SQL är inte lika med någonting så det kan inte matcha något av de överordnade ID:n (som är 1,2,3,4 och 5). Även om det fanns en NULL där, skulle den fortfarande inte matcha eftersom NULL är inte lika med någonting, inte ens NULL själv (det är en mycket konstig logik, faktiskt!). Det är därför vi använder specialkontrollen IS NULL och inte en =NULL kontrollera.

Så, kommer att Panera dyker upp om vi gör en RIGHT JOIN ? Ja det kommer det! Eftersom en RIGHT JOIN visar alla resultat som matchar (den första INNER JOIN vi gjorde) plus alla rader från RIGHT-tabellen som inte matchar (vilket i vårt fall är en, (NULL, 'Pan') rad.

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

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

Resultat:

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

Tyvärr har MySQL inte FULL JOIN . Du kan prova det i andra RDBMS, och det kommer att visa:

+------+--------+------+-------+
|  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. Hur man installerar MariaDB på CentOS 8

  2. Rails:Postgres tillstånd nekad att skapa databas på rake db:create:all

  3. Jag glömde lösenordet som jag angav under postgres-installationen

  4. Sammanfoga och gruppera flera rader i Oracle