validar vacio reemplazar por not ejemplos ejemplo campo sql sql-server tsql null notin

sql - vacio - Cláusula NOT IN y valores NULL



reemplazar null por vacio sql (11)

NOT IN devuelve 0 registros en comparación con un valor desconocido

Como NULL es una incógnita, una consulta NOT IN contenga un 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 valor NULL no sea el valor que se está probando.

Este problema surgió cuando obtuve diferentes conteos de registros para lo que pensé que eran consultas idénticas, una que not in restricción y la otra una left join . La tabla en la que not in restricción tenía un valor nulo (datos incorrectos) que hizo que la consulta devolviera un conteo de 0 registros. Entiendo por qué, pero podría necesitar alguna ayuda para comprender completamente el concepto.

Para decirlo simplemente, ¿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 estaba en SQL Server 2005. También encontré que llamar a set ansi_nulls off hace que B devuelva un resultado.


Compare to null no está definido, a menos que use IS NULL.

Por lo tanto, al comparar 3 con NULL (consulta A), devuelve undefined.

Es decir, SELECCIONE ''verdadero'' donde 3 en (1,2, nulo) y SELECCIONE ''verdadero'' donde 3 no está en (1,2, nulo)

producirá el mismo resultado, ya que NOT (UNDEFINED) aún no está definido, pero no es TRUE


Cuando usas NULL, realmente estás 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, puede probarlo fácilmente llamando a:

select ''true'' where 3 <> null select ''true'' where not (3 <> null)

Ambas consultas no te darán resultados.

Si el valor DESCONOCIDO era el mismo que FALSO, suponiendo que la primera consulta le daría FALSO, el segundo tendría que evaluar a VERDADERO como habría sido el mismo que NO (FALSO).
Ese no es el caso.

Hay un muy buen artículo sobre este tema en SqlServerCentral .

Todo el problema de NULL y la lógica de tres valores puede ser un poco confuso al principio, pero es esencial comprenderlo para escribir las consultas correctas en TSQL.

Otro artículo que recomendaría es Funciones agregadas de SQL y NULL .


De las respuestas aquí se puede concluir que NOT IN (subquery) no maneja los nulos correctamente y debe evitarse en favor de NOT EXISTS . Sin embargo, tal conclusión puede ser prematura. En el siguiente escenario, acreditado a Chris Date (Diseño y programación de bases de datos, Vol. 2, No 9, septiembre de 1989), NOT IN es NOT IN que maneja los nulos correctamente y devuelve el resultado correcto, en lugar de NOT EXISTS .

Considere una tabla sp para representar a los proveedores ( sno ) que se sabe que suministran piezas ( pno ) en cantidad ( qty ). La tabla actualmente tiene los siguientes valores:

VALUES (''S1'', ''P1'', NULL), (''S2'', ''P1'', 200), (''S3'', ''P1'', 1000)

Tenga en cuenta que la cantidad es anulable, es decir, para poder registrar el hecho de que se sabe que un proveedor suministra piezas, incluso si no se sabe en qué cantidad.

La tarea es encontrar a los proveedores que son conocidos y suministrar el número de pieza ''P1'' pero no en cantidades de 1000.

Los siguientes usos NOT IN para identificar correctamente al proveedor ''S2'' solamente:

WITH sp AS ( SELECT * FROM ( VALUES ( ''S1'', ''P1'', NULL ), ( ''S2'', ''P1'', 200 ), ( ''S3'', ''P1'', 1000 ) ) AS T ( sno, pno, qty ) ) SELECT DISTINCT spx.sno FROM sp spx WHERE spx.pno = ''P1'' AND 1000 NOT IN ( SELECT spy.qty FROM sp spy WHERE spy.sno = spx.sno AND spy.pno = ''P1'' );

Sin embargo, la consulta a continuación utiliza la misma estructura general pero con NOT EXISTS pero incluye incorrectamente el proveedor ''S1'' en el resultado (es decir, para el que la cantidad es nula):

WITH sp AS ( SELECT * FROM ( VALUES ( ''S1'', ''P1'', NULL ), ( ''S2'', ''P1'', 200 ), ( ''S3'', ''P1'', 1000 ) ) AS T ( sno, pno, qty ) ) SELECT DISTINCT spx.sno FROM sp spx WHERE spx.pno = ''P1'' AND NOT EXISTS ( SELECT * FROM sp spy WHERE spy.sno = spx.sno AND spy.pno = ''P1'' AND spy.qty = 1000 );

¡Así que NOT EXISTS no es la bala de plata que pudo haber aparecido!

Por supuesto, la fuente del problema es la presencia de nulos, por lo tanto, la solución "real" es eliminar esos nulos.

Esto se puede lograr (entre otros diseños posibles) utilizando dos tablas:

  • sp proveedores conocidos para suministrar piezas
  • spq proveedores conocidos para suministrar piezas en cantidades conocidas

teniendo en cuenta que probablemente debería haber una restricción de clave externa donde spq references sp .

El resultado se puede obtener utilizando el operador relacional ''menos'' (que es la palabra clave EXCEPT en SQL estándar), por ejemplo

WITH sp AS ( SELECT * FROM ( VALUES ( ''S1'', ''P1'' ), ( ''S2'', ''P1'' ), ( ''S3'', ''P1'' ) ) AS T ( sno, pno ) ), spq AS ( SELECT * FROM ( VALUES ( ''S2'', ''P1'', 200 ), ( ''S3'', ''P1'', 1000 ) ) AS T ( sno, pno, qty ) ) SELECT sno FROM spq WHERE pno = ''P1'' EXCEPT SELECT sno FROM spq WHERE pno = ''P1'' AND qty = 1000;


El título de esta pregunta en el momento de la escritura es

Restricción de SQL NOT IN y valores NULL

Del texto de la pregunta, parece que el problema estaba ocurriendo en una consulta SELECT DML de SQL, en lugar de una CONSTRAINT DDL de SQL.

Sin embargo, especialmente teniendo en cuenta la redacción del título, quiero señalar que algunas de las declaraciones que se hacen aquí son declaraciones potencialmente engañosas, como la de (parafraseando)

Cuando el predicado se evalúa como DESCONOCIDO, no se obtienen filas.

Aunque este es el caso de SQL DML, al considerar las restricciones, el efecto es diferente.

Considere esta tabla muy simple con dos restricciones tomadas directamente de los predicados en la pregunta (y abordada en una excelente respuesta por @Brannon):

DECLARE @T TABLE ( true CHAR(4) DEFAULT ''true'' NOT NULL, CHECK ( 3 IN (1, 2, 3, NULL )), CHECK ( 3 NOT IN (1, 2, NULL )) ); INSERT INTO @T VALUES (''true''); SELECT COUNT(*) AS tally FROM @T;

Según la respuesta de @ Brannon, la primera restricción (que usa IN ) se evalúa como VERDADERA y la segunda restricción (que usa NOT IN ) se evalúa como DESCONOCIDA. Sin embargo , la inserción tiene éxito! Por lo tanto, en este caso no es estrictamente correcto decir: "no obtiene ninguna fila" porque de hecho se insertó una fila como resultado.

El efecto anterior es, de hecho, el correcto en lo que respecta al estándar SQL-92. Compare y contraste la siguiente sección de la especificación SQL-92

7.6 donde la cláusula

El resultado de es una tabla de esas filas de T para las cuales el resultado de la condición de búsqueda es verdadero.

4.10 Restricciones de integridad

Se cumple una restricción de comprobación de tabla solo si la condición de búsqueda especificada no es falsa para ninguna fila de una tabla.

En otras palabras:

En SQL DML, las filas se eliminan del resultado cuando el WHERE evalúa como DESCONOCIDO porque no cumple la condición "es verdadero".

En SQL DDL (es decir, restricciones), las filas no se eliminan del resultado cuando se evalúan como DESCONOCIDAS porque satisface la condición "no es falso".

Aunque los efectos en SQL DML y SQL DDL respectivamente pueden parecer contradictorios, existe una razón práctica para dar a los resultados DESCONOCIDOS el "beneficio de la duda" al permitirles satisfacer una restricción (más correctamente, permitiéndoles que no dejen de satisfacer una restricción) : sin este comportamiento, todas las restricciones tendrían que manejar explícitamente los valores nulos y eso sería muy insatisfactorio desde la perspectiva del diseño del lenguaje (sin mencionar, ¡un dolor para los programadores!)

ps. si le resulta difícil seguir una lógica tal como "desconocido no deja de satisfacer una restricción" como lo hago para escribirla, entonces considere que puede prescindir de todo esto simplemente evitando las columnas que admiten valores nulos en SQL DDL y cualquier cosa en SQL DML que produce nulos (por ejemplo, combinaciones externas)!


En A, 3 se prueba la igualdad con respecto a cada miembro del conjunto, dando como resultado (FALSO, FALSO, VERDADERO, DESCONOCIDO). Dado que uno de los elementos es VERDADERO, la condición es VERDADERA. (También es posible que ocurra algún cortocircuito aquí, por lo que realmente se detiene tan pronto como llega a la primera VERDADERA y nunca evalúa 3 = NULL).

En B, creo que está evaluando la condición como NO (3 en (1,2, nulo)). Prueba 3 para la igualdad frente a los rendimientos establecidos (FALSO, FALSO, DESCONOCIDO), que se agrega a DESCONOCIDO. NO (DESCONOCIDO) rinde DESCONOCIDO. Entonces, en general, se desconoce la verdad de la condición, que al final se trata esencialmente como FALSO.


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 verdadero, 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á ansi_nulls , 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.


Nulo significa y ausencia de datos, es decir, se desconoce, no es un valor de datos de nada. Es muy fácil para la gente de un fondo de programación confundir esto porque en los lenguajes de tipo C cuando se usan punteros nulos no es nada.

Por lo tanto, en el primer caso, 3 se encuentra en el conjunto de (1,2,3, nulo), por lo que se devuelve true

En el segundo sin embargo puedes reducirlo a

seleccione ''verdadero'' donde 3 no está en (nulo)

Entonces, no se devuelve nada porque el analizador no sabe nada sobre el conjunto con el que lo está comparando, no es un conjunto vacío sino un conjunto desconocido. El uso de (1, 2, null) no ayuda porque el conjunto (1,2) es obviamente falso, pero luego estás y lo contra lo desconocido, lo cual es desconocido.


Si desea filtrar con NOT IN para una subconsulta que contenga NULLs, simplemente marque para no null

SELECT blah FROM t WHERE blah NOT IN (SELECT someotherBlah FROM t2 WHERE someotherBlah IS NOT NULL )


esto es para chico:

select party_code from abc as a where party_code not in (select party_code from xyz where party_code = a.party_code);

esto funciona independientemente de la configuración de ansi