sql >> Base de Datos >  >> RDS >> Oracle

NOT IN selección con valores NULL

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.