Toán tử EXCEPT vs KHÔNG VÀO


19

Các EXCEPTnhà đ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 INEXCEPT?

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:


29

Có hai sự khác biệt chính giữa EXCEPTNOT IN.

NGOẠI TRỪ

EXCEPTlọc các DISTINCTgiá 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 EXISTSmột DISTINCTmệ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.

KHÔNG VÀO

NOT INkhông lọc các DISTINCTgiá 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 NULLtrong 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.

THÍ DỤ

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, EXCEPTtrả về 3 hàng từ #NewCustomers, lọc ra 1 và 3 khớp #ExistingCustomersvà 8 trùng lặp.

NOT INkhông thực hiện quá trình lọc riêng biệt này và trả về 4 hàng #NewCustomersvới 8 mục trùng lặp.

Nếu bây giờ chúng ta thêm vào một NULLvào #ExistingCustomersbảng, chúng ta thấy kết quả tương tự được trả về bởi EXCEPT, tuy nhiên NOT INsẽ 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 EXISTSvà có một so sánh tốt giữa hai người trên blog của Gail Shaw .


NGOẠI TRỪ sẽ sử dụng các chỉ số nếu thích hợp?
JohnOpincar

1

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 INvớ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_namelast_namecủ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.


-2

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.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.