Các EXCEPT
nhà điều hành đã được giới thiệu trong SQL Server 2005 nhưng sự khác biệt giữa là những gì NOT IN
và EXCEPT
?
Nó có làm như vậy không? Tôi muốn một lời giải thích đơn giản với một ví dụ.
Các EXCEPT
nhà điều hành đã được giới thiệu trong SQL Server 2005 nhưng sự khác biệt giữa là những gì NOT IN
và EXCEPT
?
Nó có làm như vậy không? Tôi muốn một lời giải thích đơn giản với một ví dụ.
Câu trả lời:
Có hai sự khác biệt chính giữa EXCEPT
và NOT IN
.
EXCEPT
lọc các DISTINCT
giá trị từ bảng bên trái không xuất hiện trong bảng bên phải. Về cơ bản, nó giống như làm NOT EXISTS
một DISTINCT
mệnh đề.
Nó cũng hy vọng hai bảng (hoặc tập hợp con của các cột từ các bảng) có cùng số lượng cột ở phía bên trái và bên phải của truy vấn
Ví dụ: bạn không thể làm:
SELECT ID, Name FROM TableA
EXCEPT
SELECT ID FROM TableB
Điều này sẽ dẫn đến lỗi:
Tất cả các truy vấn được kết hợp bằng toán tử UNION, INTERSECT hoặc EXCEPT phải có số lượng biểu thức bằng nhau trong danh sách mục tiêu của chúng.
NOT IN
không lọc các DISTINCT
giá trị và trả về tất cả các giá trị từ bảng bên trái không xuất hiện trong bảng bên phải.
NOT IN
yêu cầu bạn so sánh một cột từ một bảng với một cột từ một bảng khác hoặc truy vấn con.
Ví dụ: nếu truy vấn con của bạn là trả về nhiều cột:
SELECT * FROM TableA AS nc
WHERE ID NOT IN (SELECT ID, Name FROM TableB AS ec)
Bạn sẽ nhận được lỗi sau:
Chỉ một biểu thức có thể được chỉ định trong danh sách chọn khi truy vấn con không được giới thiệu với EXISTS.
Tuy nhiên, nếu bảng bên phải chứa một NULL
trong các giá trị được lọc theo NOT IN
, một tập kết quả trống được trả về, có khả năng cho kết quả không mong muốn.
CREATE TABLE #NewCustomers (ID INT);
CREATE TABLE #ExistingCustomers (ID INT);
INSERT INTO #NewCustomers
( ID )
VALUES
(8), (9), (10), (1), (3), (8);
INSERT INTO #ExistingCustomers
( ID )
VALUES
( 1) , (2), (3), (4), (5);
-- EXCEPT filters for DISTINCT values
SELECT * FROM #NewCustomers AS nc
EXCEPT
SELECT * FROM #ExistingCustomers AS ec
-- NOT IN returns all values without filtering
SELECT * FROM #NewCustomers AS nc
WHERE ID NOT IN (SELECT ID FROM #ExistingCustomers AS ec)
Từ hai truy vấn trên, EXCEPT
trả về 3 hàng từ #NewCustomers
, lọc ra 1 và 3 khớp #ExistingCustomers
và 8 trùng lặp.
NOT IN
không thực hiện quá trình lọc riêng biệt này và trả về 4 hàng #NewCustomers
với 8 mục trùng lặp.
Nếu bây giờ chúng ta thêm vào một NULL
vào #ExistingCustomers
bảng, chúng ta thấy kết quả tương tự được trả về bởi EXCEPT
, tuy nhiên NOT IN
sẽ trả về một tập kết quả trống.
INSERT INTO #ExistingCustomers
( ID )
VALUES
( NULL );
-- With NULL values in the right-hand table, EXCEPT still returns the same results as above
SELECT * FROM #NewCustomers AS nc
EXCEPT
SELECT * FROM #ExistingCustomers AS ec
-- NOT IN now returns no results
SELECT * FROM #NewCustomers AS nc
WHERE ID NOT IN (SELECT ID FROM #ExistingCustomers AS ec)
DROP TABLE #NewCustomers;
DROP TABLE #ExistingCustomers;
Thay vì NOT IN
, bạn nên thực sự nhìn vào NOT EXISTS
và có một so sánh tốt giữa hai người trên blog của Gail Shaw .
Một bổ sung cho nhận xét tuyệt vời của Mark Sinkinson:
KHÔNG IN yêu cầu bạn so sánh một cột từ một bảng với một cột từ một bảng khác hoặc truy vấn con.
Bạn thực sự có thể thực hiện NOT IN
với nhiều hơn một cột.
Ví dụ: đây là một truy vấn SQL * hoàn toàn hợp pháp :
SELECT E.first_name, E.last_name
FROM employees E
WHERE (E.first_name, E.last_name) NOT IN
(SELECT M.first_name, M.last_name FROM managers M)
Cái nào sẽ trở lại first_name
và last_name
của tất cả những người là nhân viên, nhưng cũng không phải là người quản lý.
*: nhưng việc xây dựng chưa được triển khai trong SQL Server.
KHÔNG ở trên không thành công vì cần phải có mối tương quan giữa các vị từ trong truy vấn chính và truy vấn con. Nếu bạn để nó ra ngoài, bạn nhận được một truy vấn con UNCORRELATED.
CHỌN * TỪ TableA NHƯ nc ID KHÔNG CÓ (ID CHỌN, Tên TỪ TableB AS ec trong đó nc.ID = ec.ID)
EXCEPT tốt hơn và sẽ xử lý bất kỳ hàng null nào mà không sử dụng các vị từ IS NULL / IS NOT NULL.