Først lidt teori:Null (SQL)
De vigtigste dele for os fra ovenstående link:
Sammenligninger med NULL og logikken med tre værdier (3VL)
Da Null ikke er medlem af noget datadomæne, betragtes det ikke som en "værdi", men snarere en markør (eller pladsholder), der angiver fraværet af værdi. På grund af dette kan sammenligninger med Null aldrig resultere i hverken Sand eller Falsk, men altid i et tredje logisk resultat, Ukendt.[8] Det logiske resultat af udtrykket nedenfor, som sammenligner værdien 10 med Null, er ukendt:
SELECT 10 = NULL -- Results in Unknown
så begge sammenligninger:x = NULL
og x <> NULL
evalueres til NULL(ukendt).
SQL implementerer tre logiske resultater, så SQL-implementeringer skal sørge for en specialiseret logik med tre værdier (3VL). Reglerne for SQL-logik med tre værdier er vist i tabellerne nedenfor (p ogq repræsenterer logiske tilstande)"[9] Sandhedstabellerne SQL bruger til OG, ELLER og IKKE svarer til et fælles fragment af Kleene- og Łukasiewicz-logikken med tre værdier ( som adskiller sig i deres definition af implikation, men SQL definerer ingen sådan operation).
+---------+-------------+-------------+-------------+-----------+--------+
| p | q | p OR q | p AND q | p = q |p != q |
+---------+-------------+-------------+-------------+-----------+--------+
| True | True | True | True | True | False |
| True | False | True | False | False | True |
| True | Unknown | True | Unknown | Unknown | Unknown|
| False | True | True | False | False | True |
| False | False | False | False | True | False |
| False | Unknown | Unknown | False | Unknown | Unknown|
| Unknown | True | True | Unknown | Unknown | Unknown|
| Unknown | False | Unknown | False | Unknown | Unknown|
| Unknown | Unknown | Unknown | Unknown | Unknown | Unknown|
+---------+-------------+-------------+-------------+-----------+--------+
Effekt af Ukendt i WHERE-sætninger
SQL-logik med tre værdier støder på i Data Manipulation Language (DML) i sammenligningsprædikater for DML-sætninger og forespørgsler. WHERE-sætningen får DML-sætningen til kun at virke på de rækker, som prædikatet evaluerer til True.
Så kort sagt:WHERE-klausulen behandler NULL som FALSE
Overvej nu en enklere sag:
SELECT * FROM T1;
| X |
|--------|
| 1 |
| (null) |
og en forespørgsel:
SELECT * FROM t1 WHERE x IN (1, NULL);
Ovenstående forespørgsel er en shortland til denne:
SELECT * FROM t1
WHERE x = 1
OR x = NULL
For den anden række fra tabel t
( x =NULL) denne betingelse ser sådan ud:
WHERE NULL = 1
OR NULL = NULL
så denne betingelse for rækken x=NULL
evalueres til NULL fordi NULL=1
er NULL, NULL=NULL
er NULL og NULL OR NULL
er også NULL (se venligst tabel 3VL ovenfor).
Overvej nu mere nysgerrig sag:
SELECT * FROM t1 WHERE x NOT IN (1, NULL);
Denne klausul x NOT IN (1, NULL)
svarer til NOT ( x IN (1, NULL) )
så det svarer også til:
NOT (
x = 1
OR
x = NULL
)
og ifølge De Morgans love svarer det til:
NOT ( x = 1 ) AND NOT ( x = NULL )
og (hvis vi erstatter NOT x = y
med x <> y
) det svarer også til:
x <> 1 AND x <> NULL
Se nærmere på den sidste betingelse:
WHERE
x <> 1 AND x <> NULL
Vi kender mere end x <> NULL
evalueres altid til NULL. Vi ved også fra 3VL-tabellen ovenfor, at både true AND NULL
er NULL og false AND NULL
evalueres til FALSK, så hele betingelsen evalueres altid enten til FALSK eller NULL, men den evalueres aldrig til SAND.
Derfor en forespørgsel med denne betingelse:
SELECT .....
WHERE x NOT IN ( NULL, whatever)
giver altid tomme resultater
Og nu din forespørgsel, som også er nysgerrig:
SELECT * FROM t1
WHERE (id, val) NOT IN (select id, val from data2);
som kan omskrives (ved hjælp af konstante værdier) til:
SELECT * FROM t1
WHERE (id, val) NOT IN (
(1, null),
(2, 2 )
)
Denne forespørgsel bruger det såkaldte rækkeværdiudtryk
Dybest set en betingelse, der bruger rækkeværdien som dette
(a, b) = (x, y)
svarer til denne:
a = x AND b = y
så ovenstående forespørgsel kan omskrives til denne:
SELECT * FROM t1
WHERE NOT (
id = 1 AND val = NULL
OR
id = 2 AND val = 2
)
Ifølge De Morgans love er dette identisk med:
SELECT * FROM t1
WHERE
NOT ( id = 1 AND val = NULL )
AND
NOT ( id = 2 AND val = 2 )
og videre til:
SELECT * FROM t1
WHERE
( id <> 1 OR val <> NULL )
AND
( id <> 2 OR val <> 2 )
Siden den første del ( id <> 1 OR val <> NULL )
af betingelsen evalueres kun til sand i et tilfælde, hvor id <> 1
(se venligst 3VL-tabellen ovenfor), denne betingelse kan forenkles til:
SELECT * FROM t1
WHERE
( id <> 1 )
AND
( id <> 2 OR val <> 2 )
og videre (ifølge De Morgans love) til:
SELECT * FROM t1
WHERE
id <> 1 AND id <> 2
OR
id <> 1 AND val <> 2
så hverken (1,1)
heller ikke (2,2)
fra kilden data1
overholde disse betingelser.