Valores NULL dentro de la cláusula NOT IN
Este problema surgió cuando obtuve recuentos de registros diferentes para lo que pensé que eran consultas idénticas, una usando una not in
where
restricción y la otra usando un archivo left join
. La tabla en la not in
restricción tenía un valor nulo (datos incorrectos), lo que provocó que la consulta devolviera un recuento de 0 registros. Entiendo por qué, pero me vendría bien un poco de ayuda para comprender completamente el concepto.
En pocas palabras, ¿por qué la consulta A devuelve un resultado pero B no?
A: select 'true' where 3 in (1, 2, 3, null)
B: select 'true' where 3 not in (1, 2, null)
Esto fue en SQL Server 2005. También descubrí que llamar set ansi_nulls off
hace que B devuelva un resultado.
La consulta A es la misma que:
select 'true' where 3 = 1 or 3 = 2 or 3 = 3 or 3 = null
Como 3 = 3
es cierto, obtienes un resultado.
La consulta B es la misma que:
select 'true' where 3 <> 1 and 3 <> 2 and 3 <> null
Cuando ansi_nulls
está activado, 3 <> null
es DESCONOCIDO, por lo que el predicado se evalúa como DESCONOCIDO y no obtiene ninguna fila.
Cuando ansi_nulls
está desactivado, 3 <> null
es verdadero, por lo que el predicado se evalúa como verdadero y se obtiene una fila.
NOT IN
devuelve 0 registros cuando se compara con un valor desconocido
Dado que NULL
es desconocido, una NOT IN
consulta que contenga a NULL
o NULL
s en la lista de valores posibles siempre devolverá 0
registros ya que no hay forma de estar seguro de que el NULL
valor no es el valor que se está probando.
Siempre que usa NULL, en realidad está tratando con una lógica de tres valores.
Su primera consulta devuelve resultados cuando la cláusula WHERE se evalúa como:
3 = 1 or 3 = 2 or 3 = 3 or 3 = null
which is:
FALSE or FALSE or TRUE or UNKNOWN
which evaluates to
TRUE
El segundo:
3 <> 1 and 3 <> 2 and 3 <> null
which evaluates to:
TRUE and TRUE and UNKNOWN
which evaluates to:
UNKNOWN
DESCONOCIDO no es lo mismo que FALSO, puedes probarlo fácilmente llamando a:
select 'true' where 3 <> null
select 'true' where not (3 <> null)
Ambas consultas no le darán resultados.
Si DESCONOCIDO era lo mismo que FALSO, suponiendo que la primera consulta le daría FALSO, la segunda tendría que evaluarse como VERDADERO, ya que habría sido lo mismo que NO (FALSO).
Ese no es el caso.
Hay un muy buen artículo sobre este tema en SqlServerCentral .
Todo el tema de los NULL y la lógica de tres valores puede resultar un poco confuso al principio, pero es esencial comprenderlo para poder escribir consultas correctas en TSQL.
Otro artículo que recomendaría es SQL Aggregate Functions y NULL .