Check the documentation for IN
, specifically:
Any null values returned by subquery or expression that are compared to test_expression using IN or NOT IN return UNKNOWN. Using null values in together with IN or NOT IN can produce unexpected results.
You haven't shown them, but I'm certain that you've got at least one NULL
value lurking in your data.
You can exclude the NULL
(s) and then the NOT IN
will work as you expected:
SELECT column1 FROM Table1
WHERE column1 NOT IN (SELECT t2.column1 FROM Table2 t2
WHERE t2.column1 IS NOT NULL)
IN
and NOT IN
are, within a hand wave, opposites, but you have to keep SQL's three-valued logic in mind. Imagine we'd written the IN
using the expression form
a IN (1,2,NULL)
Which is treated the same as:
a = 1 OR a = 2 or a = NULL
For any row where a = 1, we have:
TRUE OR TRUE OR UNKNOWN
which is TRUE
. And for any row where a = 3, say, we have:
FALSE OR FALSE OR UNKNOWN
which is UNKNOWN
Now, consider NOT IN
in the same way:
a NOT IN (1,2,NULL)
Which is treated the same as:
a != 1 AND a != 2 AND a != NULL
For any row where a = 1, we have:
FALSE AND TRUE AND UNKNOWN
Which is FALSE
. And for a = 3, we have:
TRUE AND TRUE AND UNKNOWN
Which is UNKNOWN
. The presence of the NULL
means that there's no way to ever get this chain of AND
s to produce a TRUE
value.