sql >> Database teknologi >  >> RDS >> Oracle

Brug af IS NULL eller IS NOT NULL på joinbetingelser - Teorispørgsmål

Eksempel med tabel A og B:

 A (forælder) B (barn) ==========================id | navn pid | navn ------------ ------------ 1 | Alex 1 | Kate 2 | Bill 1 | Lia 3 | Cath 3 | Mary 4 | Dale NULL | Pan 5 | Evan  

Hvis du vil finde forældre og deres børn, laver du en INNER JOIN :

VÆLG id, forælder.navn SOM forælder , pid, barn.navn SOM barnFRA forælder INNER JOIN barn PÅ parent.id =barn.pid 

Resultatet er, at hvert match af en forælder s id fra den venstre tabel og et underordnet s pid fra den anden tabel vises som en række i resultatet:

+----+--------+------+-------+| id | forælder | pid | barn | +----+--------+------+-------+| 1 | Alex | 1 | Kate || 1 | Alex | 1 | Lia || 3 | Cath | 3 | Mary |+----+--------+------+------+

Nu viser ovenstående ikke forældre uden børn (fordi deres id'er ikke har et match i barnets id'er, så hvad gør du? Du laver en ydre joinforbindelse i stedet for. Der er tre typer af outer joins, den venstre, den højre og den fulde ydre joinforbindelse. Vi skal bruge den venstre, da vi vil have de "ekstra" rækker fra den venstre tabel (forælder):

VÆLG id, forælder.navn SOM forælder , pid, barn.navn SOM barnFRA forælder VENSTRE JOIN barn PÅ parent.id =barn.pid 

Resultatet er, at udover tidligere kampe, vises alle forældre, der ikke har et match (læs:ikke har et barn), også:

+----+--------+------+-------+| id | forælder | pid | barn | +----+--------+------+-------+| 1 | Alex | 1 | Kate || 1 | Alex | 1 | Lia || 3 | Cath | 3 | Mary || 2 | Bill | NULL | NULL || 4 | Dale | NULL | NULL || 5 | Evan | NULL | NULL |+----+--------+------+------+

Hvor blev alle de NULL kommer fra? Nå, MySQL (eller ethvert andet RDBMS, du måtte bruge) ved ikke, hvad de skal placere der, da disse forældre ikke har noget match (barn), så der er ingen pid heller ikke barn.navn at matche med de forældre. Så den sætter denne specielle ikke-værdi kaldet NULL .

Min pointe er, at disse NULLs oprettes (i resultatsættet) under LEFT OUTER JOIN .

Så hvis vi kun vil vise de forældre, der IKKE har et barn, kan vi tilføje en WHERE child.pid IS NULL til LEFT JOIN over. Koden HVOR klausulen evalueres (afkrydset) efter JOIN Er gjort. Så det er klart ud fra ovenstående resultat, at kun de sidste tre rækker, hvor pid er NULL vil blive vist:

VÆLG id, forælder.navn SOM forælder , pid, barn.navn SOM barn FRA forælder VENSTRE JOIN barn PÅ parent.id =barn.pid. HVOR barn.pid ER NULL 

Resultat:

+----+--------+------+-------+| id | forælder | pid | barn | +----+--------+------+-------+| 2 | Bill | NULL | NULL || 4 | Dale | NULL | NULL || 5 | Evan | NULL | NULL |+----+--------+------+------+

Hvad sker der nu, hvis vi flytter den ER NULL tjek fra WHERE til den tilsluttede ON klausul?

VÆLG id, forælder.navn SOM forælder , pid, barn.navn SOM barn FRA forælder VENSTRE JOIN barn PÅ parent.id =barn.pid OG barn.pid ER NULL 

I dette tilfælde forsøger databasen at finde rækker fra de to tabeller, der matcher disse betingelser. Det vil sige rækker hvor parent.id =child.pid OG child.pid IN NULL . Men den kan finde ingen sådan match fordi ingen child.pid kan være lig med noget (1, 2, 3, 4 eller 5) og være NULL på samme tid!

Så betingelsen:

ON parent.id =child.pidAND child.pid ER NULL 

svarer til:

ON 1 =0 

som altid er False .

Så hvorfor returnerer den ALLE rækker fra den venstre tabel? Fordi det er et LEFT JOIN! Og venstre joinforbindelse returnerer rækker, der matcher (ingen i dette tilfælde) og også rækker fra den venstre tabel, der ikke matcher checken (alt i dette tilfælde ):

+----+--------+------+-------+| id | forælder | pid | barn | +----+--------+------+-------+| 1 | Alex | NULL | NULL || 2 | Bill | NULL | NULL || 3 | Cath | NULL | NULL || 4 | Dale | NULL | NULL || 5 | Evan | NULL | NULL |+----+--------+------+------+

Jeg håber, at ovenstående forklaring er klar.

Sidenote (ikke direkte relateret til dit spørgsmål):Hvorfor i alverden panorerer ikke dukke op i ingen af ​​vores JOINs? Fordi hans pid er NULL og NULL i (ikke almindelig) logik i SQL er ikke lig med noget, så det kan ikke matche med nogen af ​​de overordnede id'er (som er 1,2,3,4 og 5). Selvom der var en NULL der, ville den stadig ikke matche, fordi NULL er ikke lig med noget, ikke engang NULL sig selv (det er en meget mærkelig logik, ja!). Det er derfor, vi bruger den særlige check IS NULL og ikke en =NULL tjek.

Så vil Panorere dukke op, hvis vi laver en RIGHT JOIN ? Ja, det vil! Fordi en RIGHT JOIN vil vise alle resultater, der matcher (den første INNER JOIN, vi gjorde) plus alle rækker fra RIGHT-tabellen, der ikke matcher (som i vores tilfælde er én, (NULL, 'Pan') række.

VÆLG id, forælder.navn SOM forælder , pid, barn.navn SOM barn FRA forælder HØJRE JOIN barn PÅ parent.id =barn.pid 

Resultat:

+------+--------+------+-------+| id | forælder | pid | barn | +---------------+------+-------+| 1 | Alex | 1 | Kate || 1 | Alex | 1 | Lia || 3 | Cath | 3 | Mary || NULL | NULL | NULL | Panorer |+------+--------+------+-------+

Desværre har MySQL ikke FULD JOIN . Du kan prøve det i andre RDBMS'er, og det vil vise:

+------+--------+------+-------+| id | forælder | pid | barn | +------+--------+------+------+| 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 | Panorer |+------+--------+------+-------+

  1. Sådan gendannes database ved hjælp af RMAN

  2. Udskiftning af mysql_*-funktioner med PDO og forberedte udsagn

  3. Værdien af ​​data over tid

  4. Få autogenereret nøgle fra rækkeindsættelse i foråret 3 / PostgreSQL 8.4.9