Eerst wat theorie:Null (SQL)
De belangrijkste onderdelen voor ons uit bovenstaande link:
Vergelijkingen met NULL en de driewaardige logica (3VL)
Aangezien Null geen lid is van een gegevensdomein, wordt het niet als een "waarde" beschouwd, maar eerder als een markering (of tijdelijke aanduiding) die de afwezigheid van waarde aangeeft. Hierdoor kunnen vergelijkingen met Null nooit resulteren in True of False, maar altijd in een derde logisch resultaat, Unknown.[8] Het logische resultaat van de onderstaande uitdrukking, die de waarde 10 vergelijkt met Null, is Onbekend:
SELECT 10 = NULL -- Results in Unknown
zodat beide vergelijkingen:x = NULL
en x <> NULL
evalueert naar NULL(onbekend).
SQL implementeert drie logische resultaten, dus SQL-implementaties moeten zorgen voor een gespecialiseerde driewaardige logica (3VL). De regels die de driewaardige logica van SQL regelen, worden weergegeven in de onderstaande tabellen (p en q vertegenwoordigen logische toestanden)"[9] De waarheidstabellen die SQL gebruikt voor AND, OR en NIET komen overeen met een algemeen fragment van de Kleene en Łukasiewicz driewaardige logica ( die verschillen in hun definitie van implicatie, maar SQL definieert zo'n bewerking niet).
+---------+-------------+-------------+-------------+-----------+--------+ | 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| +---------+-------------+-------------+-------------+-----------+--------+
Effect van Unknown in WHERE-clausules
Driewaardige SQL-logica wordt aangetroffen in Data Manipulation Language (DML) in vergelijkingspredikaten van DML-instructies en -query's. De WHERE-clausule zorgt ervoor dat de DML-instructie alleen werkt op die rijen waarvoor het predikaat True evalueert.
Dus in het kort:WHERE-clausule behandelt NULL als FALSE
Overweeg nu een eenvoudiger geval:
SELECT * FROM T1;
| X |
|--------|
| 1 |
| (null) |
en een vraag:
SELECT * FROM t1 WHERE x IN (1, NULL);
De bovenstaande vraag is een shortland naar deze:
SELECT * FROM t1
WHERE x = 1
OR x = NULL
Voor de tweede rij uit tabel t
( x =NULL) deze voorwaarde ziet er als volgt uit:
WHERE NULL = 1
OR NULL = NULL
dus deze voorwaarde voor de rij x=NULL
evalueert naar NULL omdat NULL=1
is NULL, NULL=NULL
is NULL, en NULL OR NULL
is ook NULL (zie tabel 3VL hierboven).
Overweeg nu een meer merkwaardig geval:
SELECT * FROM t1 WHERE x NOT IN (1, NULL);
Deze clausule x NOT IN (1, NULL)
is gelijk aan NOT ( x IN (1, NULL) )
dus het is ook gelijk aan:
NOT (
x = 1
OR
x = NULL
)
en volgens de wetten van De Morgan is het gelijk aan:
NOT ( x = 1 ) AND NOT ( x = NULL )
en (als we NOT x = y
vervangen met x <> y
) het is ook gelijk aan:
x <> 1 AND x <> NULL
Kijk goed naar de laatste voorwaarde:
WHERE
x <> 1 AND x <> NULL
We weten dan x <> NULL
evalueert altijd naar NULL. We weten ook uit de 3VL-tabel hierboven dat zowel true AND NULL
is NULL en false AND NULL
evalueert naar FALSE, dus de hele voorwaarde evalueert altijd naar FALSE of NULL, maar evalueert nooit naar TRUE.
Daarom een zoekopdracht met deze voorwaarde:
SELECT .....
WHERE x NOT IN ( NULL, whatever)
retourneert altijd een lege resultatenset
En nu uw vraag, die ook nieuwsgierig is:
SELECT * FROM t1
WHERE (id, val) NOT IN (select id, val from data2);
die kan worden herschreven (met constante waarden) naar:
SELECT * FROM t1
WHERE (id, val) NOT IN (
(1, null),
(2, 2 )
)
Deze query gebruikt de zogenaamde rijwaarde-expressie
In wezen een voorwaarde die de rijwaarde als deze gebruikt
(a, b) = (x, y)
is gelijk aan deze:
a = x AND b = y
zodat de bovenstaande vraag kan worden herschreven in deze:
SELECT * FROM t1
WHERE NOT (
id = 1 AND val = NULL
OR
id = 2 AND val = 2
)
Volgens de wetten van De Morgan is dit identiek aan:
SELECT * FROM t1
WHERE
NOT ( id = 1 AND val = NULL )
AND
NOT ( id = 2 AND val = 2 )
en verder naar:
SELECT * FROM t1
WHERE
( id <> 1 OR val <> NULL )
AND
( id <> 2 OR val <> 2 )
Sinds het eerste deel ( id <> 1 OR val <> NULL )
van de voorwaarde evalueert alleen waar als id <> 1
(zie de 3VL-tabel hierboven), deze voorwaarde kan worden vereenvoudigd tot:
SELECT * FROM t1
WHERE
( id <> 1 )
AND
( id <> 2 OR val <> 2 )
en verder (volgens de wetten van De Morgan) in:
SELECT * FROM t1
WHERE
id <> 1 AND id <> 2
OR
id <> 1 AND val <> 2
dus geen van beide (1,1)
noch (2,2)
van de bron data1
aan deze voorwaarden voldoen.