За исключением оператора против не в

Ответы:

29

Есть два ключевых различия между 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и есть хорошее сравнение между ними в блоге Гейл Шоу .

Марк Синкинсон
источник
Будут ли ИСКЛЮЧЕНЫ индексы, если это уместно?
JohnOpincar
1

Дополнение к превосходному комментарию Марка Синкинсона:

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 * FROM TableA AS nc, ГДЕ НЕ ИДЕНТИФИКАТОР (SELECT ID, имя FROM TableB AS, где nc.ID = ec.ID)

EXCEPT лучше и будет обрабатывать любые пустые строки без использования предикатов IS NULL / IS NOT NULL.

Бертон Р Лид
источник