sql >> Databáze >  >> RDS >> Oracle

NOT IN výběr s hodnotami NULL

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.



  1. C#:Ekvivalence datového typu Oracle s OracleDbType

  2. Jak zkrátit tabulku v postupu Oracle?

  3. Jak zacházet s jednou citací v Oracle SQL

  4. Jak opravit výstrahu Security Advisor MySQL