SELECT foreignStockId
FROM [Subset].[dbo].[Products]
Renvoie probablement un NULL
.
Un NOT IN
la requête ne renverra aucune ligne s'il y en a NULL
s existe dans la liste des NOT IN
valeurs. Vous pouvez les exclure explicitement en utilisant IS NOT NULL
comme ci-dessous.
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)
Ou réécrivez en utilisant NOT EXISTS
à la place.
SELECT stock.idstock,
stock.descr
FROM [Inventory].[dbo].[Stock] stock
WHERE NOT EXISTS (SELECT *
FROM [Subset].[dbo].[Products] p
WHERE p.foreignstockid = stock.idstock)
En plus d'avoir la sémantique que vous souhaitez, le plan d'exécution pour NOT EXISTS
est souvent plus simple comme on le voit ici.
La raison de la différence de comportement est due à la logique à trois valeurs utilisée dans SQL. Les prédicats peuvent être évalués à True
, False
, ou Unknown
.
Un WHERE
la clause doit être évaluée à True
pour que la ligne soit retournée mais ce n'est pas possible avec NOT IN
quand NULL
est présent comme expliqué ci-dessous.
'A' NOT IN ('X','Y',NULL)
est équivalent à 'A' <> 'X' AND 'A' <> 'Y' AND 'A' <> NULL)
- 'A' <> 'X' =
True
- 'A' <> 'O' =
True
- 'A' <> NULL =
Unknown
True AND True AND Unknown
est évalué à Unknown
selon les tables de vérité pour la logique à trois valeurs.
Les liens suivants contiennent des informations supplémentaires sur les performances des différentes options.
- Dois-je utiliser
NOT IN
,OUTER APPLY
,LEFT OUTER JOIN
,EXCEPT
, ouNOT EXISTS
? NOT IN
vsNOT EXISTS
vsLEFT JOIN / IS NULL
:SQL ServerLeft outer join
vsNOT EXISTS
NOT EXISTS
vsNOT IN