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 терпит неудачу, потому что должна быть корреляция между предикатами в основном запросе и подзапросе. Если вы пропустите это, вы получите некоррелированный подзапрос.
SELECT * FROM TableA AS nc, ГДЕ НЕ ИДЕНТИФИКАТОР (SELECT ID, имя FROM TableB AS, где nc.ID = ec.ID)
EXCEPT лучше и будет обрабатывать любые пустые строки без использования предикатов IS NULL / IS NOT NULL.