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.