EXCEPT
Оператор був введений в SQL Server 2005 , але в чому різниця між NOT IN
і EXCEPT
?
Чи робить це те саме? Мені б хотілося простого пояснення з прикладом.
EXCEPT
Оператор був введений в SQL Server 2005 , але в чому різниця між NOT IN
і EXCEPT
?
Чи робить це те саме? Мені б хотілося простого пояснення з прикладом.
Відповіді:
Існує дві ключові відмінності між EXCEPT
та NOT 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.
Однак, якщо в правій таблиці міститься 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.
Якщо ми тепер додамо в 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
і в блозі Гейл Шоу є хороше порівняння між ними .
Доповнення до відмінного коментаря Марка Сінкінсона:
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.
Звернення NOT IN не вдається, оскільки має бути співвідношення предикатів у головному запиті та підзапиті. Якщо ви не залишите його, ви отримаєте непідписаний підзапит.
ВИБІР * З ТАБЛИЦІ AS AS nc, де ідентифікується НЕ (SELECT ID, ім'я від TableB як ec, де nc.ID = ec.ID)
EXCEPT краще і буде обробляти будь-які нульові рядки без використання предикатів IS NULL / IS NOT NULL.