JuniorKỹ thuậtSQL
Vì sao NOT IN có thể không trả dòng nào và nên dùng gì thay thế?
Thử trả lời trước
Đáp án mẫu
x NOT IN (a, b, NULL) được khai triển thành x <> a AND x <> b AND x <> NULL. Vế cuối là UNKNOWN, nên toàn bộ điều kiện không bao giờ TRUE, và WHERE trả về không dòng nào. Chỉ một NULL trong danh sách đã âm thầm làm rỗng kết quả.
-- returns nothing if any employee has manager_id NULL
SELECT name FROM employees
WHERE id NOT IN (SELECT manager_id FROM employees);
Lỗi này hay gặp vì các cột như manager_id có thể NULL và CEO không có manager.
Hai lựa chọn an toàn:
-- NOT EXISTS: NULL-safe, usually the best
SELECT e.name FROM employees e
WHERE NOT EXISTS (
SELECT 1 FROM employees m WHERE m.manager_id = e.id
);
-- LEFT JOIN anti join
SELECT e.name FROM employees e
LEFT JOIN employees m ON m.manager_id = e.id
WHERE m.id IS NULL;
Bạn cũng có thể lọc subquery bằng WHERE manager_id IS NOT NULL. Planner của hầu hết engine biến NOT EXISTS và join thành anti join hiệu quả.
Hãy ưu tiên NOT EXISTS mỗi khi cột của subquery có thể NULL.
Ý chính
- Một NULL trong danh sách NOT IN làm điều kiện UNKNOWN với mọi dòng
- NOT EXISTS an toàn với NULL
- LEFT JOIN kèm IS NULL là một cách anti join khác
- Planner tối ưu cả hai thành anti join
Câu hỏi nối tiếp thường gặp
- Vấn đề này có ảnh hưởng đến IN không?
Lỗi thường gặp
- Dùng NOT IN trên cột subquery có thể NULL
- Chỉ test trên dữ liệu tình cờ không có NULL