Primero un poco de teoría:Nulo (SQL)
Las partes más importantes para nosotros del enlace anterior:
Comparaciones con NULL y la lógica de tres valores (3VL)
Dado que Null no es miembro de ningún dominio de datos, no se considera un "valor", sino un marcador (o marcador de posición) que indica la ausencia de valor. Debido a esto, las comparaciones con Nulo nunca pueden resultar en Verdadero o Falso, sino siempre en un tercer resultado lógico, Desconocido.[8] El resultado lógico de la siguiente expresión, que compara el valor 10 con Nulo, es Desconocido:
SELECT 10 = NULL -- Results in Unknown
para que ambas comparaciones:x = NULL
y x <> NULL
se evalúa como NULL (desconocido).
SQL implementa tres resultados lógicos, por lo que las implementaciones de SQL deben proporcionar una lógica especializada de tres valores (3VL). Las reglas que gobiernan la lógica de tres valores de SQL se muestran en las siguientes tablas (p y q representan estados lógicos)"[9] Las tablas de verdad que utiliza SQL para AND, OR y NOT corresponden a un fragmento común de la lógica de tres valores de Kleene y Łukasiewicz ( que difieren en su definición de implicación, sin embargo, SQL no define tal operación).
+---------+-------------+-------------+-------------+-----------+--------+
| 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|
+---------+-------------+-------------+-------------+-----------+--------+
Efecto de Desconocido en las cláusulas WHERE
La lógica de tres valores de SQL se encuentra en el lenguaje de manipulación de datos (DML) en predicados de comparación de declaraciones y consultas DML. La cláusula WHERE hace que la declaración DML actúe solo en aquellas filas para las cuales el predicado se evalúa como Verdadero.
En resumen:la cláusula WHERE trata a NULL como FALSO
Ahora considere un caso más simple:
SELECT * FROM T1;
| X |
|--------|
| 1 |
| (null) |
y una consulta:
SELECT * FROM t1 WHERE x IN (1, NULL);
La consulta anterior es una abreviatura de esta:
SELECT * FROM t1
WHERE x = 1
OR x = NULL
Para la segunda fila de la tabla t
( x =NULL) esta condición se parece a:
WHERE NULL = 1
OR NULL = NULL
entonces esta condición para la fila x=NULL
se evalúa como NULL porque NULL=1
es NULL, NULL=NULL
es NULL, y NULL OR NULL
también es NULL (consulte la tabla 3VL anterior).
Ahora considere un caso más curioso:
SELECT * FROM t1 WHERE x NOT IN (1, NULL);
Esta cláusula x NOT IN (1, NULL)
es equivalente a NOT ( x IN (1, NULL) )
por lo que también es equivalente a:
NOT (
x = 1
OR
x = NULL
)
y según las leyes de De Morgan es equivalente a:
NOT ( x = 1 ) AND NOT ( x = NULL )
y (si reemplazamos NOT x = y
con x <> y
) también es equivalente a:
x <> 1 AND x <> NULL
Mire detenidamente la última condición:
WHERE
x <> 1 AND x <> NULL
Sabemos que x <> NULL
siempre se evalúa como NULL. También sabemos por la tabla 3VL anterior, que tanto true AND NULL
es NULL y false AND NULL
se evalúa como FALSO, por lo que toda la condición siempre se evalúa como FALSO o NULL, pero nunca se evalúa como VERDADERO.
Por lo tanto, una consulta con esta condición:
SELECT .....
WHERE x NOT IN ( NULL, whatever)
siempre devuelve un conjunto de resultados vacío
Y ahora tu consulta, que también es curiosa:
SELECT * FROM t1
WHERE (id, val) NOT IN (select id, val from data2);
que se puede reescribir (usando valores constantes) a:
SELECT * FROM t1
WHERE (id, val) NOT IN (
(1, null),
(2, 2 )
)
Esta consulta utiliza la llamada expresión de valor de fila
Básicamente, una condición que utiliza la expresión de valor de fila como esta
(a, b) = (x, y)
es equivalente a este:
a = x AND b = y
por lo que la consulta anterior se puede reescribir en esta:
SELECT * FROM t1
WHERE NOT (
id = 1 AND val = NULL
OR
id = 2 AND val = 2
)
De acuerdo con las leyes de De Morgan, esto es idéntico a:
SELECT * FROM t1
WHERE
NOT ( id = 1 AND val = NULL )
AND
NOT ( id = 2 AND val = 2 )
y más allá de:
SELECT * FROM t1
WHERE
( id <> 1 OR val <> NULL )
AND
( id <> 2 OR val <> 2 )
Desde la primera parte ( id <> 1 OR val <> NULL )
de la condición se evalúa como verdadera solo en un caso donde id <> 1
(consulte la tabla 3VL anterior), esta condición se puede simplificar en:
SELECT * FROM t1
WHERE
( id <> 1 )
AND
( id <> 2 OR val <> 2 )
y más (según las leyes de De Morgan) en:
SELECT * FROM t1
WHERE
id <> 1 AND id <> 2
OR
id <> 1 AND val <> 2
entonces tampoco (1,1)
ni (2,2)
de la fuente data1
cumplir con estas condiciones.