web-dev-qa-db-fra.com

SAUF opérateur vs PAS DANS

L'opérateur EXCEPT a été introduit dans SQL Server 2005 mais quelle est la différence entre NOT IN et EXCEPT?

Fait-il la même chose? Je voudrais une explication simple avec un exemple.

19
Heisenberg

Il existe deux différences clés entre EXCEPT et NOT IN.

SAUF

EXCEPT filtre les valeurs DISTINCT du tableau de gauche qui n'apparaissent pas dans le tableau de droite. C'est essentiellement la même chose que de faire un NOT EXISTS avec une clause DISTINCT.

Il s'attend également à ce que les deux tables (ou sous-ensemble de colonnes des tables) aient le même nombre de colonnes à gauche et à droite de la requête

Par exemple, vous ne pouvez pas faire:

SELECT ID, Name FROM TableA
EXCEPT
SELECT ID FROM TableB

Cela entraînerait l'erreur:

Toutes les requêtes combinées à l'aide d'un opérateur UNION, INTERSECT ou EXCEPT doivent avoir un nombre égal d'expressions dans leurs listes cibles.

PAS DEDANS

NOT IN ne filtre pas les valeurs DISTINCT et renvoie toutes les valeurs du tableau de gauche qui n'apparaissent pas dans le tableau de droite.

NOT IN vous oblige à comparer une seule colonne d'une table avec une seule colonne d'une autre table ou sous-requête.

Par exemple, si votre sous-requête devait renvoyer plusieurs colonnes:

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

Vous obtiendrez l'erreur suivante:

Une seule expression peut être spécifiée dans la liste de sélection lorsque la sous-requête n'est pas introduite avec EXISTS.

Cependant, si le tableau de droite contient un NULL dans les valeurs filtrées par NOT IN, un jeu de résultats vide est renvoyé, ce qui peut donner des résultats inattendus.

EXEMPLE

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)

À partir des deux requêtes ci-dessus, EXCEPT renvoie 3 lignes de #NewCustomers, filtrant les 1 et 3 correspondant à #ExistingCustomers et le doublon 8.

NOT IN ne fait pas ce filtrage distinct et renvoie 4 lignes à partir de #NewCustomers avec le doublon 8.

Si nous ajoutons maintenant un NULL au #ExistingCustomers table, nous voyons les mêmes résultats retournés par EXCEPT, cependant NOT IN renverra un jeu de résultats vide.

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;

Au lieu de NOT IN, vous devriez vraiment regarder NOT EXISTS et il y a une bonne comparaison entre les deux sur le blog de Gail Shaw .

30
Mark Sinkinson

Un ajout à l'excellent commentaire de Mark Sinkinson:

NOT IN vous oblige à comparer une seule colonne d'une table avec une seule colonne d'une autre table ou sous-requête.

Vous pouvez, en fait, effectuer NOT IN avec plusieurs colonnes.
Par exemple. ceci est parfaitement légal* Requête 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)

Qui renverra first_name et last_name de toutes les personnes qui sont des employés, mais qui ne sont pas également des managers.

*: mais la construction n'est pas encore implémentée dans SQL Server.

1
Michael Vigato