SELECT foreignStockId
FROM [Subset].[dbo].[Products]
Probablemente devuelve un NULL
.
UN NOT IN
la consulta no devolverá ninguna fila si alguna NULL
s existe en la lista de NOT IN
valores. Puede excluirlos explícitamente usando IS NOT NULL
como se muestra a continuación.
SELECT stock.IdStock,
stock.Descr
FROM [Inventory].[dbo].[Stock] stock
WHERE stock.IdStock NOT IN (SELECT foreignStockId
FROM [Subset].[dbo].[Products]
WHERE foreignStockId IS NOT NULL)
O reescribe usando NOT EXISTS
en su lugar.
SELECT stock.idstock,
stock.descr
FROM [Inventory].[dbo].[Stock] stock
WHERE NOT EXISTS (SELECT *
FROM [Subset].[dbo].[Products] p
WHERE p.foreignstockid = stock.idstock)
Además de tener la semántica que desea, el plan de ejecución para NOT EXISTS
a menudo es más simple como se ve aquí.
La razón de la diferencia en el comportamiento se debe a la lógica de tres valores utilizada en SQL. Los predicados pueden evaluarse como True
, False
o Unknown
.
Un WHERE
la cláusula debe evaluarse como True
para que se devuelva la fila, pero esto no es posible con NOT IN
cuando NULL
está presente como se explica a continuación.
'A' NOT IN ('X','Y',NULL)
es equivalente a 'A' <> 'X' AND 'A' <> 'Y' AND 'A' <> NULL)
- 'A' <> 'X' =
True
- 'A' <> 'Y' =
True
- 'A' <> NULL =
Unknown
True AND True AND Unknown
se evalúa como Unknown
según las tablas de verdad para la lógica de tres valores.
Los siguientes enlaces tienen una discusión adicional sobre el rendimiento de las diversas opciones.
- ¿Debería usar
NOT IN
? ,OUTER APPLY
,LEFT OUTER JOIN
,EXCEPT
, oNOT EXISTS
? NOT IN
frente aNOT EXISTS
frente aLEFT JOIN / IS NULL
:Servidor SQLLeft outer join
vsNOT EXISTS
NOT EXISTS
vsNOT IN