This is by design. If the match fails and the set contains NULL, the result will be NULL as specified by the SQL standard.
'1' IN ('1', '3') => true
'2' IN ('1', '3') => false
'1' IN ('1', NULL) => true
'2' IN ('1', NULL) => NULL
'1' NOT IN ('1', '3') => false
'2' NOT IN ('1', '3') => true
'1' NOT IN ('1', NULL) => false
'2' NOT IN ('1', NULL) => NULL
Informally, the logic is that NULL can be considered as an unknown value. For example, it does not matter here that the unknown value - β1β is explicitly indicated in the set, so the result is correct.
'1' IN ('1', NULL) => true
In the following example, we cannot be sure that β2β is in the set, but since we do not know all the values, we also cannot be sure that it is not in the set. So the result is NULL.
'2' IN ('1', NULL) => NULL
Another way to look at this is to rewrite x NOT IN (Y, Z) as X <> Y AND X <> Z Then you can use the three-valued logic rules:
true AND NULL => NULL false AND NULL => false
source share