Это по замыслу. Если совпадение не удается и набор содержит NULL, результат равен NULL, как указано в стандарте SQL.
'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
Неформально логика, стоящая за этим, заключается в том, что NULL может рассматриваться как неизвестное значение. Например, здесь не имеет значения, что представляет собой неизвестное значение - «1» явно находится в наборе, поэтому результат верен.
'1' IN ('1', NULL) => true
В следующем примере мы не можем быть уверены, что '2' есть в наборе, но так как мы не знаем всех значений, мы также не можем быть уверены, что это не в наборе. Таким образом, результат равен NULL.
'2' IN ('1', NULL) => NULL
Еще один способ взглянуть на это - переписать x NOT IN (Y, Z)
как X <> Y AND X <> Z
. Тогда вы можете использовать правила трехзначной логики :
true AND NULL => NULL
false AND NULL => false