Có thể kết luận từ các câu trả lời ở đây là NOT IN (subquery)
không xử lý null một cách chính xác và nên tránh có lợi cho NOT EXISTS
. Tuy nhiên, kết luận như vậy có thể là sớm. Trong kịch bản sau đây, được ghi có vào Chris Date (Thiết kế và lập trình cơ sở dữ liệu, Tập 2 số 9, tháng 9 năm 1989), đó là NOT IN
xử lý null chính xác và trả về kết quả chính xác, thay vìNOT EXISTS
.
Xem xét một bảng sp
để đại diện cho các nhà cung cấp ( sno
) được biết là cung cấp các bộ phận ( pno
) về số lượng ( qty
). Bảng hiện đang giữ các giá trị sau:
VALUES ('S1', 'P1', NULL),
('S2', 'P1', 200),
('S3', 'P1', 1000)
Lưu ý rằng số lượng là không có nghĩa là có thể ghi lại thực tế nhà cung cấp được biết là cung cấp các bộ phận ngay cả khi không biết số lượng.
Nhiệm vụ là tìm các nhà cung cấp được biết là số bộ phận cung cấp 'P1' nhưng không phải với số lượng 1000.
Cách sử dụng sau đây NOT IN
để xác định chính xác chỉ nhà cung cấp 'S2':
WITH sp AS
( SELECT *
FROM ( VALUES ( 'S1', 'P1', NULL ),
( 'S2', 'P1', 200 ),
( 'S3', 'P1', 1000 ) )
AS T ( sno, pno, qty )
)
SELECT DISTINCT spx.sno
FROM sp spx
WHERE spx.pno = 'P1'
AND 1000 NOT IN (
SELECT spy.qty
FROM sp spy
WHERE spy.sno = spx.sno
AND spy.pno = 'P1'
);
Tuy nhiên, truy vấn bên dưới sử dụng cùng một cấu trúc chung nhưng với NOT EXISTS
nhưng không chính xác bao gồm nhà cung cấp 'S1' trong kết quả (nghĩa là số lượng là null):
WITH sp AS
( SELECT *
FROM ( VALUES ( 'S1', 'P1', NULL ),
( 'S2', 'P1', 200 ),
( 'S3', 'P1', 1000 ) )
AS T ( sno, pno, qty )
)
SELECT DISTINCT spx.sno
FROM sp spx
WHERE spx.pno = 'P1'
AND NOT EXISTS (
SELECT *
FROM sp spy
WHERE spy.sno = spx.sno
AND spy.pno = 'P1'
AND spy.qty = 1000
);
Vì vậy, NOT EXISTS
không phải là viên đạn bạc nó có thể đã xuất hiện!
Tất nhiên, nguồn gốc của vấn đề là sự hiện diện của null, do đó, giải pháp 'thực tế' là loại bỏ những null đó.
Điều này có thể đạt được (trong số các thiết kế có thể khác) bằng cách sử dụng hai bảng:
sp
nhà cung cấp được biết đến để cung cấp các bộ phận
spq
nhà cung cấp được biết đến để cung cấp các bộ phận với số lượng được biết đến
lưu ý có lẽ nên có một ràng buộc khóa ngoài nơi spq
tham chiếu sp
.
Kết quả sau đó có thể thu được bằng cách sử dụng toán tử quan hệ 'trừ' (là EXCEPT
từ khóa trong SQL chuẩn), vd
WITH sp AS
( SELECT *
FROM ( VALUES ( 'S1', 'P1' ),
( 'S2', 'P1' ),
( 'S3', 'P1' ) )
AS T ( sno, pno )
),
spq AS
( SELECT *
FROM ( VALUES ( 'S2', 'P1', 200 ),
( 'S3', 'P1', 1000 ) )
AS T ( sno, pno, qty )
)
SELECT sno
FROM spq
WHERE pno = 'P1'
EXCEPT
SELECT sno
FROM spq
WHERE pno = 'P1'
AND qty = 1000;
NOT IN
sang một loạt các<> and
thay đổi hành vi ngữ nghĩa không có trong bộ này sang thứ khác không?