Họ đang đo gì
Bạn có nắm logic ba trạng thái không. Đây là nguồn gốc của cả một họ bug im lặng: NOT IN, <>, và UNIQUE cho phép nhiều NULL.
Trả lời ngắn~30 giây
Trả về NULL, tức UNKNOWN, chứ không phải TRUE. NULL nghĩa là “không biết giá trị”, mà hai giá trị không biết thì không thể kết luận là bằng nhau. Muốn so sánh bằng cả khi cùng NULL thì dùng IS NOT DISTINCT FROM (Postgres) hoặc toán tử <=> (MySQL).
Giải thích sâu
Hệ quả trực tiếp nhất là WHERE chỉ giữ hàng khi điều kiện đúng là TRUE. UNKNOWN bị loại y như FALSE, nên WHERE deleted_at <> '2020-01-01' sẽ bỏ qua mọi hàng có deleted_at IS NULL — trong khi ý định của người viết gần như chắc chắn là giữ chúng.
Cái bẫy đắt hơn là NOT IN (subquery). Nếu subquery trả về dù chỉ một NULL, toàn bộ biểu thức không bao giờ TRUE được nữa, và truy vấn trả về rỗng — không lỗi, không cảnh báo. NOT EXISTS không có vấn đề này vì nó làm việc với sự tồn tại của hàng chứ không so sánh giá trị. Đó là lý do nhiều nhóm quy ước dùng NOT EXISTS mặc định.
Cùng logic đó giải thích vì sao ràng buộc UNIQUE cho phép nhiều hàng NULL trong hầu hết engine: hai NULL không được coi là trùng nhau. Postgres 15 thêm UNIQUE NULLS NOT DISTINCT để đảo lại hành vi này khi bạn cần.
SELECT NULL = NULL; -- NULL (không phải true)
SELECT NULL <> 1; -- NULL
SELECT NULL IS NULL; -- true
SELECT 1 IS NOT DISTINCT FROM NULL; -- false, và không bao giờ NULL
-- Trả về 0 hàng nếu blocked_ids chứa dù chỉ một NULL:
SELECT * FROM users WHERE id NOT IN (SELECT blocked_id FROM blocks);
-- An toàn với NULL:
SELECT * FROM users u
WHERE NOT EXISTS (SELECT 1 FROM blocks b WHERE b.blocked_id = u.id);Câu hỏi tiếp theo họ sẽ hỏi
?count(*) và count(cot) khác nhau chỗ nào?
count(*) đếm hàng; count(cot) đếm hàng có cot khác NULL. Chênh lệch giữa hai số chính là số NULL — một cách kiểm tra chất lượng dữ liệu rất nhanh.
?NULL ảnh hưởng tới index không?
Có. Postgres lưu NULL trong B-tree nên IS NULL vẫn dùng được index; Oracle thì không lưu NULL trong index B-tree thường, nên truy vấn IS NULL phải quét bảng. Đây là khác biệt engine cần nói rõ thay vì khẳng định chung chung.
Trả lời thế này là mất điểm
- Trả lời “TRUE, vì hai bên giống nhau”. Đây là câu sàng lọc — sai là mất tín nhiệm cho cả phần SQL còn lại.
- Coi NULL là 0 hoặc chuỗi rỗng. Ba thứ này khác nhau và trộn lẫn chúng là nguồn lỗi thật trong migration.