Câu 1Câu nào mô tả đúng WHERE EXISTS (SELECT 1 FROM sales sale WHERE sale.emp_id = emp.emp_id)?
EXISTS và truy vấn con tương quan
Học SQL EXISTS và truy vấn con tương quan: EXISTS / NOT EXISTS, cách né an toàn cạm bẫy NOT IN + NULL bằng EXISTS, và khi nào chọn EXISTS thay vì IN — thực hành trên dữ liệu nhân viên và doanh số, tất cả chạy trực tiếp trên trình duyệt của bạn.
Dữ liệu dùng trong bài viết này — employee / sales / department
EXISTS là một truy vấn con chỉ kiểm tra liệu có ít nhất một hàng khớp tồn tại hay không, và bạn dùng nó khá giống IN.
Trong bài viết này bạn sẽ đi qua những điều cơ bản của EXISTS / NOT EXISTS, cách né an toàn cạm bẫy NOT IN + NULL bằng cách viết nó với EXISTS, và cách chọn giữa EXISTS và IN dựa trên khả năng đọc.
Dữ liệu là ba bảng dữ liệu nhân viên.
Dùng employee (30 nhân viên), sales (50 dòng doanh số), và department (6 phòng ban), bạn sẽ lấy ra "nhân viên có / không có doanh số" và "phòng ban không có nhân viên".
EXISTS / NOT EXISTS — chỉ kiểm tra liệu một hàng có tồn tại hay không
WHERE EXISTS (SELECT ... ) là true nếu truy vấn con trả về dù chỉ một hàng, và false nếu nó không trả về hàng nào cả.
Truy vấn con select gì không ảnh hưởng đến kết quả, nên theo quy ước bạn viết SELECT 1 (giá trị không được dùng — bạn chỉ quan tâm liệu một hàng có tồn tại hay không).
Dạng cơ bản là một truy vấn con tương quan tham chiếu một cột từ truy vấn chính bên trong EXISTS.
"Nhân viên có doanh số" là WHERE EXISTS (SELECT 1 FROM sales sale WHERE sale.emp_id = emp.emp_id), và "nhân viên không có doanh số" là phủ định của nó, NOT EXISTS.
EXISTS ngừng đánh giá ngay khi nó tìm thấy một hàng, điều này khiến nó phù hợp cho việc kiểm tra tồn tại.
-- EXISTS: nhân viên có doanh số
SELECT emp.emp_id, emp.name
FROM employee emp
WHERE EXISTS (
SELECT 1 FROM sales sale WHERE sale.emp_id = emp.emp_id
)
ORDER BY emp.emp_id;
Cạm bẫy NOT IN + NULL — EXISTS thì an toàn
Nếu bạn viết "lọc phủ định" bằng NOT IN, kết quả có thể trả về 0 hàng khi một NULL bị trộn vào phía truy vấn con.
x NOT IN (1, 2, NULL) được đánh giá là "x không phải 1, không phải 2, và không phải NULL," nhưng x <> NULL không bao giờ thành true và luôn là NULL (không xác định), nên toàn bộ NOT IN không bao giờ thành true.
Lý lẽ đầy đủ được giải thích trong Truy vấn con ① (cạm bẫy NOT IN + NULL).
Vì employee.dept_id trộn NULL, viết "phòng ban không có nhân viên" thành WHERE dept_id NOT IN (SELECT dept_id FROM employee) khiến Legal (một phòng ban hoàn toàn không có nhân viên), lẽ ra phải có, biến mất và kết quả trả về 0 hàng.
NOT EXISTS chỉ nhìn vào liệu một hàng có tồn tại hay không và không bị NULL ảnh hưởng, nên trong tình huống này NOT EXISTS trả về kết quả đúng.
-- Cạm bẫy: một truy vấn con chứa NULL + NOT IN trả về 0 hàng
SELECT dept_id, dept_name
FROM department
WHERE dept_id NOT IN (SELECT dept_id FROM employee);
-- → 0 hàng vì employee.dept_id chứa NULL
-- An toàn: NOT EXISTS không bị NULL ảnh hưởng
SELECT d.dept_id, d.dept_name
FROM department d
WHERE NOT EXISTS (
SELECT 1 FROM employee emp WHERE emp.dept_id = d.dept_id
);
Chọn EXISTS theo khả năng đọc
EXISTS chỉ nhìn vào liệu một hàng có tồn tại hay không, nên nó an toàn ngay cả khi có NULL, nhưng viết một truy vấn con tương quan có thể khiến nó trông dài hơn IN.
Với một phép kiểm tra tồn tại đơn giản có những tình huống mà IN đọc tốt hơn, và trong công việc thực tế bạn chọn dựa trên ngữ cảnh.
Mặt khác, với một phủ định như NOT IN nơi NULL phá vỡ kết quả, hoặc khi bạn muốn phán định một cách chắc chắn chỉ liệu một hàng có tồn tại hay không, EXISTS / NOT EXISTS là lựa chọn an toàn.
Kiểm tra kiến thức
Hãy trả lời từng câu hỏi một.
Câu 2Khi một NULL có thể trộn vào phía truy vấn con, vấn đề gì có thể xảy ra nếu bạn viết lọc phủ định bằng NOT IN?
Câu 3Câu nào là cách phù hợp để quyết định giữa EXISTS và IN?