EXCEPTO operador vs NO EN

Respuestas:

29

Hay dos diferencias clave entre EXCEPTy NOT IN.

EXCEPTO

EXCEPTfiltra los DISTINCTvalores de la tabla de la izquierda que no aparecen en la tabla de la derecha. Es esencialmente lo mismo que hacer un NOT EXISTScon una DISTINCTcláusula.

También espera que las dos tablas (o subconjunto de columnas de las tablas) tengan el mismo número de columnas en el lado izquierdo y derecho de la consulta

Por ejemplo, no puedes hacer:

SELECT ID, Name FROM TableA
EXCEPT
SELECT ID FROM TableB

Esto provocaría el error:

Todas las consultas combinadas con un operador UNION, INTERSECT o EXCEPT deben tener el mismo número de expresiones en sus listas de destino.

NO EN

NOT INno filtra los DISTINCTvalores y devuelve todos los valores de la tabla de la izquierda que no aparecen en la tabla de la derecha.

NOT IN requiere que compare una sola columna de una tabla con una sola columna de otra tabla o subconsulta.

Por ejemplo, si su subconsulta debía devolver varias columnas:

SELECT * FROM TableA AS nc
WHERE ID NOT IN (SELECT ID, Name FROM TableB AS ec)

Obtendría el siguiente error:

Solo se puede especificar una expresión en la lista de selección cuando la subconsulta no se introduce con EXISTS.

Sin embargo, si la tabla de la derecha contiene a NULLen los valores que se filtran NOT IN, se devuelve un conjunto de resultados vacío, lo que puede dar resultados inesperados.

EJEMPLO

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)

De las dos consultas anteriores, EXCEPTdevuelve 3 filas de #NewCustomers, filtrando el 1 y 3 que coinciden #ExistingCustomersy el duplicado 8.

NOT INno realiza este filtrado distinto y devuelve 4 filas #NewCustomerscon el duplicado 8.

Si ahora agregamos un NULLa la #ExistingCustomerstabla, vemos los mismos resultados devueltos por EXCEPT, sin embargo NOT IN, devolverá un conjunto de resultados vacío.

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;

En lugar de eso NOT IN, realmente deberías mirar NOT EXISTSy hay una buena comparación entre los dos en el blog de Gail Shaw .

Mark Sinkinson
fuente
¿EXCEPTO utilizará índices si corresponde?
JohnOpincar
1

Una adición al excelente comentario de Mark Sinkinson:

NOT IN requiere que compare una sola columna de una tabla con una sola columna de otra tabla o subconsulta.

En realidad, puede actuar NOT INcon más de una columna.
Por ejemplo, esta es una consulta SQL * perfectamente 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 volverá first_nameylast_name de todas las personas que son empleados, pero no son también gerentes.

*: pero la construcción aún no está implementada en SQL Server.

Michael Vigato
fuente
-2

El NOT IN anterior falla porque debe haber una correlación entre los predicados en la consulta principal y la subconsulta. Si lo deja fuera, obtiene una subconsulta SIN CORREGIR.

SELECT * FROM TableA AS nc WHERE ID NOT IN (SELECT ID, Name FROM TableB AS ec donde nc.ID = ec.ID)

EXCEPTO es mejor y manejará cualquier fila nula sin usar predicados IS NULL / IS NOT NULL.

Burton R Leed
fuente