Nejprve trocha teorie:Null (SQL)
Nejdůležitější části pro nás z výše uvedeného odkazu:
Srovnání s NULL a tříhodnotovou logikou (3VL)
Protože Null není členem žádné datové domény, nepovažuje se za „hodnotu“, ale spíše za značku (nebo zástupný symbol) označující nepřítomnost hodnoty. Z tohoto důvodu nemůže srovnání s Null nikdy vyústit buď v pravdivé nebo nepravdivé, ale vždy ve třetí logický výsledek, Neznámý.[8] Logický výsledek výrazu níže, který porovnává hodnotu 10 s hodnotou Null, je Neznámý:
SELECT 10 = NULL -- Results in Unknown
takže obě srovnání:x = NULL
a x <> NULL
vyhodnotí jako NULL(neznámé).
SQL implementuje tři logické výsledky, takže implementace SQL musí poskytovat specializovanou logiku se třemi hodnotami (3VL). Pravidla, jimiž se řídí trojhodnotová logika SQL, jsou uvedena v tabulkách níže (p aq představují logické stavy)"[9] Pravdivé tabulky, které SQL používá pro AND, OR, a NOT odpovídají společnému fragmentu logiky tří hodnot Kleene a Łukasiewicz ( které se liší ve své definici implikace, avšak SQL žádnou takovou operaci nedefinuje).
+---------+-------------+-------------+-------------+-----------+--------+ | 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| +---------+-------------+-------------+-------------+-----------+--------+
Účinek Neznámý v klauzuli WHERE
Tříhodnotová logika SQL se vyskytuje v jazyce Data Manipulation Language (DML) v predikátech porovnání příkazů a dotazů DML. Klauzule WHERE způsobí, že příkaz DML působí pouze na ty řádky, pro které je predikát vyhodnocen jako True.
Takže stručně:klauzule WHERE považuje NULL za FALSE
Nyní zvažte jednodušší případ:
SELECT * FROM T1;
| X |
|--------|
| 1 |
| (null) |
a dotaz:
SELECT * FROM t1 WHERE x IN (1, NULL);
Výše uvedený dotaz je zkratkou k tomuto:
SELECT * FROM t1
WHERE x = 1
OR x = NULL
Pro druhý řádek z tabulky t
( x =NULL) tato podmínka vypadá takto:
WHERE NULL = 1
OR NULL = NULL
takže tato podmínka pro řádek x=NULL
vyhodnotí se jako NULL, protože NULL=1
je NULL, NULL=NULL
je NULL a NULL OR NULL
je také NULL (viz tabulka 3VL výše).
Nyní zvažte kurióznější případ:
SELECT * FROM t1 WHERE x NOT IN (1, NULL);
Tato klauzule x NOT IN (1, NULL)
je ekvivalentní NOT ( x IN (1, NULL) )
takže je také ekvivalentní:
NOT (
x = 1
OR
x = NULL
)
a podle De Morganových zákonů je ekvivalentní:
NOT ( x = 1 ) AND NOT ( x = NULL )
a (pokud nahradíme NOT x = y
s x <> y
) je také ekvivalentní:
x <> 1 AND x <> NULL
Podívejte se prosím pozorně na poslední podmínku:
WHERE
x <> 1 AND x <> NULL
Známe než x <> NULL
vždy se vyhodnotí jako NULL. Z výše uvedené tabulky 3VL také víme, že true AND NULL
je NULL a false AND NULL
vyhodnotí jako FALSE, takže celá podmínka se vždy vyhodnotí buď jako FALSE nebo NULL, ale nikdy se nevyhodnotí jako TRUE.
Proto dotaz s touto podmínkou:
SELECT .....
WHERE x NOT IN ( NULL, whatever)
vždy vrací prázdnou sadu výsledků
A nyní váš dotaz, který je také kuriózní:
SELECT * FROM t1
WHERE (id, val) NOT IN (select id, val from data2);
který lze přepsat (pomocí konstantních hodnot) na:
SELECT * FROM t1
WHERE (id, val) NOT IN (
(1, null),
(2, 2 )
)
Tento dotaz používá tzv. výraz hodnoty řádku
V podstatě podmínku využívající výraz hodnoty řádku, jako je tento
(a, b) = (x, y)
je ekvivalentní tomuto:
a = x AND b = y
takže výše uvedený dotaz lze přepsat do tohoto:
SELECT * FROM t1
WHERE NOT (
id = 1 AND val = NULL
OR
id = 2 AND val = 2
)
Podle De Morganových zákonů je to totožné s:
SELECT * FROM t1
WHERE
NOT ( id = 1 AND val = NULL )
AND
NOT ( id = 2 AND val = 2 )
a dále na:
SELECT * FROM t1
WHERE
( id <> 1 OR val <> NULL )
AND
( id <> 2 OR val <> 2 )
Od první části ( id <> 1 OR val <> NULL )
podmínky se vyhodnotí jako true pouze v případě, kdy id <> 1
(viz tabulka 3VL výše), tuto podmínku lze zjednodušit na:
SELECT * FROM t1
WHERE
( id <> 1 )
AND
( id <> 2 OR val <> 2 )
a dále (podle De Morganových zákonů) do:
SELECT * FROM t1
WHERE
id <> 1 AND id <> 2
OR
id <> 1 AND val <> 2
takže ani (1,1)
ani (2,2)
ze zdroje data1
dodržovat tyto podmínky.