SAUF opérateur vs PAS DANS

Réponses:

29

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

SAUF

EXCEPTfiltre les DISTINCTvaleurs 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 EXISTSavec une DISTINCTclause.

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 INne filtre pas les DISTINCTvaleurs 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 NULLdans les valeurs filtrées 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, EXCEPTrenvoie 3 lignes de #NewCustomers, en filtrant les 1 et 3 qui correspondent #ExistingCustomerset le 8 en double.

NOT INne fait pas ce filtrage distinct et renvoie 4 lignes #NewCustomersavec le duplicata 8.

Si nous ajoutons maintenant a NULLà la #ExistingCustomerstable, nous voyons les mêmes résultats renvoyés par EXCEPT, mais NOT INnous retournerons 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 cela NOT IN, vous devriez vraiment regarder NOT EXISTSet il y a une bonne comparaison entre les deux sur le blog de Gail Shaw .

Mark Sinkinson
la source
EXCEPT utilisera-t-il des indices le cas échéant?
JohnOpincar
1

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, jouer NOT INavec plus d'une colonne.
Par exemple, il s'agit d'une requête SQL * parfaitement légale :

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 reviendra first_nameet last_namede toutes les personnes qui sont des salariés, mais qui ne sont pas aussi des managers.

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

Michael Vigato
la source
-2

Le NOT IN ci-dessus échoue car il doit y avoir une corrélation entre les prédicats de la requête principale et de la sous-requête. Si vous l'omettez, vous obtenez une sous-requête NON CORRIGÉE.

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

EXCEPT est meilleur et gérera toutes les lignes nulles sans utiliser les prédicats IS NULL / IS NOT NULL.

Burton R Leed
la source