Vì NOT IN được khai triển thành chuỗi AND các phép khác (<>), mà so sánh với NULL cho ra UNKNOWN chứ không phải TRUE/FALSE.
Chỉ cần một NULL trong danh sách là toàn bộ điều kiện không bao giờ TRUE → không dòng nào lọt.
sql
-- customers_without_orders: tra ve 0 dong neu orders.customer_id co NULL
SELECT * FROM customers
WHERE id NOT IN (SELECT customer_id FROM orders);
-- id NOT IN (1, 2, NULL)
-- <=> id <> 1 AND id <> 2 AND id <> NULL
-- <=> TRUE AND TRUE AND UNKNOWN = UNKNOWNBa cách sửa, theo thứ tự nên dùng:
sql
-- 1. NOT EXISTS: an toan voi NULL, thuong toi uu tot nhat
SELECT * FROM customers c
WHERE NOT EXISTS (SELECT 1 FROM orders o WHERE o.customer_id = c.id);
-- 2. LEFT JOIN ... IS NULL (anti-join thu cong)
SELECT c.* FROM customers c
LEFT JOIN orders o ON o.customer_id = c.id
WHERE o.customer_id IS NULL;
-- 3. loc NULL truoc khi dua vao NOT IN
WHERE id NOT IN (SELECT customer_id FROM orders WHERE customer_id IS NOT NULL);Điểm khác biệt cốt lõi: NOT EXISTS dùng ngữ nghĩa "có tồn tại dòng nào khớp không" nên NULL không gây UNKNOWN. IN (dương) thì không bị lỗi này — chỉ NOT IN mới nguy hiểm.