Problems / The NOT IN + NULL Trap / Editorial
WHERE customer_id NOT IN (SELECT customer_id FROM orders)
orders.customer_id
x NOT IN (list)
x <> v1 AND x <> v2 AND ... AND x <> NULL
WHERE
NOT EXISTS (SELECT 1 FROM orders o WHERE o.customer_id = c.customer_id)
NOT EXISTS
o.customer_id = c.customer_id
NOT IN
WHERE customer_id IS NOT NULL
customer_id
NOT IN against a set containing NULL is the classic silent SQL failure: no error, no warning, just an empty result. IN degrades gracefully with NULLs (TRUE still wins the OR-chain), but NOT IN needs every comparison to be TRUE, and NULL poisons the chain. NOT EXISTS — and PySpark's left_anti join — implement anti-join semantics that treat NULLs as non-matches, which is what you almost always want.
IN
left_anti
Solve The NOT IN + NULL Trap yourself →