The scenario is very simple. You want to get all ID’s from one table that does not exists in another table.
This is how the two simple tables are set up.
DECLARE @Table1 TABLE
(
ID INT
)
INSERT @Table1
SELECT 1 UNION ALL
SELECT 2 UNION ALL
SELECT 3 UNION ALL
SELECT 4 UNION ALL
SELECT 5 UNION ALL
SELECT 6 UNION ALL
SELECT 7
DECLARE @Table2 TABLE
(
ID INT
)
INSERT @Table2
SELECT 1 UNION ALL
SELECT 3 UNION ALL
SELECT 4 UNION ALL
SELECT 5 UNION ALL
SELECT 7 UNION ALL
SELECT NULL
Now you run this piece of code to get the missing ID’s, right?
SELECT t1.ID
FROM @Table1 AS t1
WHERE t1.ID NOT IN (SELECT x.ID FROM @Table2 AS x)
But wait! Why did the I get an empty resultset in return? I should get ID 2 and 6 back.
The reason to this perhaps unexpected result is that you have a NULL value in the IN list. When the SQL Engine tries to match the outer values from Table1 with the values taken from Table2 in the IN list, a match against NULL is unknown. So we can’t decide if the outer value exists or not, so the SQL Engine does not return the value, because it is interpreted as the outer value exists in the IN list.
You can solve this by writing an extra WHERE in the IN clause, like this
SELECT t1.ID
FROM @Table1 AS t1
WHERE t1.ID NOT IN (SELECT x.ID FROM @Table2 AS x WHERE x.ID IS NOT NULL)
Now you get ID’s 2 and 6 back.