O EXCEPT
operador foi introduzido no SQL Server 2005, mas qual é a diferença entre NOT IN
e EXCEPT
?
Faz o mesmo? Eu gostaria de uma explicação simples com um exemplo.
O EXCEPT
operador foi introduzido no SQL Server 2005, mas qual é a diferença entre NOT IN
e EXCEPT
?
Faz o mesmo? Eu gostaria de uma explicação simples com um exemplo.
Respostas:
Existem duas diferenças principais entre EXCEPT
e NOT IN
.
EXCEPT
filtra os DISTINCT
valores da tabela à esquerda que não aparecem na tabela à direita. É essencialmente o mesmo que fazer a NOT EXISTS
com uma DISTINCT
cláusula.
Ele também espera que as duas tabelas (ou subconjunto de colunas das tabelas) tenham o mesmo número de colunas no lado esquerdo e direito da consulta
Por exemplo, você não pode fazer:
SELECT ID, Name FROM TableA
EXCEPT
SELECT ID FROM TableB
Isso resultaria no erro:
Todas as consultas combinadas usando um operador UNION, INTERSECT ou EXCEPT devem ter um número igual de expressões em suas listas de destino.
NOT IN
não filtra DISTINCT
valores e retorna todos os valores da tabela à esquerda que não aparecem na tabela à direita.
NOT IN
requer que você compare uma única coluna de uma tabela com uma única coluna de outra tabela ou subconsulta.
Por exemplo, se sua subconsulta deveria retornar várias colunas:
SELECT * FROM TableA AS nc
WHERE ID NOT IN (SELECT ID, Name FROM TableB AS ec)
Você receberá o seguinte erro:
Somente uma expressão pode ser especificada na lista de seleção quando a subconsulta não é introduzida com EXISTS.
No entanto, se a tabela à direita contiver um NULL
nos valores que estão sendo filtrados NOT IN
, um conjunto de resultados vazio será retornado, potencialmente fornecendo resultados inesperados.
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)
Das duas consultas acima, EXCEPT
retorna 3 linhas #NewCustomers
, filtrando o 1 e o 3 que correspondem #ExistingCustomers
e o 8 duplicado.
NOT IN
não faz essa filtragem distinta e retorna 4 linhas #NewCustomers
com o 8 duplicado.
Se agora adicionarmos NULL
a à #ExistingCustomers
tabela, veremos os mesmos resultados retornados por EXCEPT
, no entanto NOT IN
, retornará um conjunto de resultados vazio.
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;
Em vez disso NOT IN
, você deve realmente olhar NOT EXISTS
e há uma boa comparação entre os dois no blog de Gail Shaw .
Uma adição ao excelente comentário de Mark Sinkinson:
NOT IN requer que você compare uma única coluna de uma tabela com uma única coluna de outra tabela ou subconsulta.
Na verdade, você pode executar NOT IN
com mais de uma coluna.
Por exemplo, esta é uma consulta SQL * prefectly legal :
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)
Que retornará first_name
e last_name
de todas as pessoas que são funcionários, mas também não são gerentes.
*: mas a construção ainda não foi implementada no SQL Server.
O NOT IN acima falha porque é necessário haver uma correlação entre os predicados na consulta principal e a subconsulta. Se você deixar de fora, você obtém uma subconsulta NÃO CORRETA.
SELECT * FROM TableA AS nc ONDE ID NÃO ESTÁ (SELECT ID, Nome FROM TableB AS ec onde nc.ID = ec.ID)
EXCEPT é melhor e manipulará qualquer linha nula sem usar os predicados IS NULL / IS NOT NULL.