ยกเว้นผู้ประกอบการ vs NOT IN


19

ตัวEXCEPTดำเนินการถูกนำมาใช้ใน SQL Server 2005 แต่ความแตกต่างระหว่างNOT INและEXCEPTคืออะไร

มันทำเช่นเดียวกัน? ฉันต้องการคำอธิบายง่ายๆพร้อมตัวอย่าง

คำตอบ:


29

มีสองความแตกต่างที่สำคัญระหว่างมีและEXCEPTNOT IN

ยกเว้น

EXCEPTกรองDISTINCTค่าจากตารางด้านซ้ายที่ไม่ปรากฏในตารางทางขวา มันเป็นหลักเช่นเดียวกับการทำNOT EXISTSด้วยDISTINCTประโยค

นอกจากนี้ยังคาดว่าทั้งสองตาราง (หรือส่วนย่อยของคอลัมน์จากตาราง) จะมีจำนวนคอลัมน์เท่ากันในด้านซ้ายและด้านขวาของแบบสอบถาม

ตัวอย่างเช่นคุณไม่สามารถทำได้:

SELECT ID, Name FROM TableA
EXCEPT
SELECT ID FROM TableB

สิ่งนี้จะส่งผลให้เกิดข้อผิดพลาด:

แบบสอบถามทั้งหมดที่รวมกันโดยใช้ตัวดำเนินการ UNION, INTERSECT หรือ EXCEPT จะต้องมีจำนวนนิพจน์ที่เท่ากันในรายการเป้าหมาย

ไม่เข้า

NOT INไม่กรองDISTINCTค่าและส่งคืนค่าทั้งหมดจากตารางด้านซ้ายที่ไม่ปรากฏในตารางด้านขวา

NOT IN คุณต้องการเปรียบเทียบคอลัมน์เดียวจากตารางหนึ่งกับคอลัมน์เดียวจากตารางหรือแบบสอบถามย่อยอื่น

ตัวอย่างเช่นหากแบบสอบถามย่อยของคุณส่งคืนคอลัมน์หลายคอลัมน์:

SELECT * FROM TableA AS nc
WHERE ID NOT IN (SELECT ID, Name FROM TableB AS ec)

คุณจะได้รับข้อผิดพลาดดังต่อไปนี้:

สามารถระบุได้เพียงนิพจน์เดียวในรายการที่เลือกเมื่อไม่ได้แนะนำเคียวรีย่อยด้วย EXISTS

อย่างไรก็ตามหากตารางด้านขวามี a NULLในค่าที่ถูกกรองโดยNOT INชุดผลลัพธ์ที่ว่างเปล่าจะถูกส่งกลับอาจทำให้ได้ผลลัพธ์ที่ไม่คาดคิด

ตัวอย่าง

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)

จากแบบสอบถามสองข้อด้านบนให้EXCEPTส่งคืน 3 แถวจาก#NewCustomersกรอง 1 และ 3 ที่ตรงกัน#ExistingCustomersและซ้ำ 8

NOT INไม่ทำการกรองที่แตกต่างกันและส่งคืน 4 แถวจาก#NewCustomersด้วยซ้ำ 8

หากเราเพิ่มใน a NULLไปยัง#ExistingCustomersตารางเราจะเห็นผลลัพธ์เดียวกันที่ส่งคืนโดยEXCEPTอย่างไรก็ตามNOT INจะส่งคืนชุดผลลัพธ์ที่ว่างเปล่า

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;

แทนที่จะNOT INคุณจริงๆควรดูที่NOT EXISTSและมีการเปรียบเทียบที่ดีระหว่างสองบล็อกเกลชอว์


ยกเว้นจะใช้ดัชนีตามความเหมาะสมหรือไม่
JohnOpincar

1

การเพิ่มความคิดเห็นที่ยอดเยี่ยมของ Mark Sinkinson:

NOT IN กำหนดให้คุณเปรียบเทียบคอลัมน์เดียวจากตารางหนึ่งกับคอลัมน์เดียวจากตารางหรือแบบสอบถามย่อยอื่น

จริงๆแล้วคุณสามารถทำได้NOT INโดยมีมากกว่าหนึ่งคอลัมน์
เช่นนี้เป็นแบบสอบถาม SQL * ที่ถูกกฎหมาย:

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)

ซึ่งจะส่งคืนfirst_nameและlast_nameจากทุกคนที่เป็นพนักงาน แต่ไม่ใช่ผู้จัดการ

*: แต่การก่อสร้างยังไม่ได้นำมาใช้ใน SQL Server


-2

NOT IN ด้านบนล้มเหลวเนื่องจากจำเป็นต้องมีความสัมพันธ์ระหว่างเพรดิเคตในเคียวรีหลักและเคียวรีย่อย ถ้าคุณปล่อยให้มันออกคุณจะได้รับแบบสอบถามย่อยที่ไม่เกี่ยวข้อง

SELECT * จาก TableA AS nc ที่ ID ไม่อยู่ใน (เลือก ID, ชื่อจาก TableB AS ec โดยที่ nc.ID = ec.ID)

ยกเว้นจะดีกว่าและจะจัดการกับแถว null ใด ๆ โดยไม่ใช้ IS NULL / IS ไม่ใช่เพรดิเคตที่เป็นโมฆะ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.