sql >> Database >  >> RDS >> Oracle

NIET IN selectie met NULL-waarden

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.



  1. Het standaardspoor verwijderen - Deel 3

  2. Een Access-database koppelen aan SQL Server in Access 2016

  3. Krijg het aantal records beïnvloed door INSERT of UPDATE in PostgreSQL

  4. Hoe de sortering van een tabel in MySQL te tonen