Lógica de tres valores de SQL Server y cláusula NOT IN con valores NULL

Al consultar el servidor de producción para resolver un problema crítico, de repente, una consulta me llamó la atención por completo. Habíamos escrito una consulta que fue creada. para buscar registros que existen en la Tabla A pero que no existen en la Tabla B, basado en una columna determinada. La consulta fue sintácticamente correcta y se ejecutó sin errores, pero no arrojó ningún resultado. Hubo algunos registros que esperábamos obtener en los resultados, por lo que investigamos la razón por la cual la consulta correcta no devolvió ninguno.

los NO EN cláusula devuelve filas de la tabla externa que no existen en la tabla interna utilizada en la subconsulta. En este tutorial, examinaremos el uso de la cláusula NOT IN con valores nulos.

Ejemplo de la cláusula NOT IN

SELECT * FROM OuterTable WHERE PK_Id NOT IN (SELECT FK_id from InnerTable); 

Ejemplo de la cláusula NOT IN con valores NULL en tabla interna.

CREAR EL PRODUCTO DE TABLA (PK_Product_Id INT CLAVE PRIMARIA, nombre VARCHAR (255)); INSERTE EN LOS VALORES DEL PRODUCTO (1, 'Coca Cola'), (2, 'Pepsi'), (3, 'Mango'), (4, '7 Arriba'); CREAR TABLA PRODUCT_DETAILS (PK_Details_Id INT PRIMARY KEY, [Description] VARCHAR (500), FK_Product_Id INT FOREIGN KEY REFERENCES PRODUCT (PK_Product_Id)); INTRODUCIR EN LOS VALORES DE LOS PRODUCTOS POR DIARIO (100, '500 ML es bueno', 1); INTRODUZCA LOS VALORES DE LOS PRODUCTOS POR DIARIO (101, '500 ML es bueno', 2); INTRODUCIR EN LOS VALORES DE PRODUCTOS POR DIARIO (102, '500 ML es bueno', 3); INTRODUZCA EN LOS VALORES DE LOS PRODUCTOS POR DIARIO (103, '500 ML es bueno', NULL); 

Como se muestra en la imagen de arriba, la tabla PRODUCT_DETAILS contiene una Valor nulo.

Ahora, nuestro objetivo es para averiguar los nombres de los productos de la tabla de productos cuyos detalles no están disponibles en la tabla Detalles de producto. Idealmente, debería devolver el Producto 4 de la tabla Producto ya que los detalles del Producto 4 no existen en la tabla Product_Details.

Podríamos pensar que esto se puede lograr fácilmente usando el predicado NOT IN escribiendo la siguiente consulta.

SELECCIONAR * DEL PRODUCTO DONDE PK_Product_Id NO EN (SELECCIONE Fk_Product_Id FROM PRODUCT_DETAILS); 

La consulta anterior no devuelve nada, aunque sintácticamente es correcta. Debido a la existencia de un valor NULL en la tabla Product_Details, no se pueden devolver los resultados esperados.

SQL Server utiliza el Lógica de tres valores concepto aquí

Como sabemos, existe un valor NULL en la tabla Product_Details en la columna fk_product_id. UNA El valor NULL es un valor desconocido o faltante.

SQL Server convierte la cláusula NOT IN utilizando una lógica de tres valores y la evalúa de la siguiente manera.

NO EN (SELECCIONE 1 O 2 O 3 O NULL) NO EN (Fk_product_id = 1 O Fk_product_id = 2 O Fk_product_id = 3 O Fk_product_id = NULL) NO EN (Fk_product_id = 1 O Fk_product_id = 2 O Fk_product_id = 3 OR Desconocido) (VERDADERO O VERDADERO O VERDADERO O DESCONOCIDO) NO EN (VERDADERO O VERDADERO O DESCONOCIDO) NO EN (VERDADERO O DESCONOCIDO) NO EN (DESCONOCIDO) 

Como el el resultado final se evalúa como DESCONOCIDO, la consulta NOT IN no devuelve ningún resultado debido a la existencia de un valor NULL.

La solución es hacer que las consultas NOT IN funcionen con la existencia de valores NULL y usar una lógica de dos valores, solo TRUE o FALSE.

- NO EN CON NO ES NULL Filtro SELECCIONE * DESDE EL PRODUCTO DONDE PK_Product_Id NO EN (SELECCIONE Fk_Product_Id DESDE PRODUCT_DETAILS DONDE Fk_Product_Id NO ES NULO); - NO EXISTE SELECT * FROM PRODUCT Prd DONDE NO EXISTE (SELECT Fk_Product_Id FROM PRODUCT_DETAILS WHERE Fk_Product_Id = Prd.PK_Product_Id); 

NOT EXISTS también nos proporciona los resultados correctos porque utiliza lógica booleana de dos valores, solo TRUE o False, para filtrar las filas.

--Utilizando Left Join SELECT * FROM PRODUCT Prd LEFT JOIN PRODUCT_DETAILS PrdDetails ON Prd. PK_Product_Id = PrdDetails .FK_Product_Id DONDE PrdDetails. FK_Product_Id es nulo 

Al usar la combinación izquierda, también podemos recuperar los registros que existen en la tabla Producto pero no en la página Detalles del producto cuando hacemos una combinación basada en la clave principal (pk_product_id) y la clave externa (fk_product_id).