Si b es anulable, esto no es un error. El problema es que SQL Server convierte NOT IN en una serie de <> 1 AND <> 2 AND <> 3 etc. Si tiene <> NULL , que devuelve unknown, que en este caso significa false. En diferentes escenarios esto puede calificar o descalificar a TODOS filas En lugar de LEFT JOIN acercarse, debe decir:
FROM dbo.OuterTable AS t
WHERE NOT EXISTS (SELECT 1 FROM x WHERE b = t.a);
Aquí hay una demostración rápida:
DECLARE @x TABLE(i INT);
INSERT @x VALUES(1),(2);
DECLARE @y TABLE(j INT);
INSERT @y VALUES(2),(NULL);
SELECT i FROM @x WHERE i NOT IN -- produces zero results
(SELECT j FROM @y);
SELECT i FROM @x AS x WHERE NOT EXISTS -- produces one result
(SELECT 1 FROM @y WHERE j = x.i);
Para obtener muchos más detalles (y métricas para demostrar por qué NOT EXISTS es la mejor alternativa):
https://www.sqlperformance.com /2012/12/t-sql-queries/left-anti-semi-join
Además, lea esta publicación de blog de Gail Shaw:
https://sqlinthewild. co.za/index.php/2010/02/18/not-exists-vs-not-in/