Database
 sql >> Base de données >  >> RDS >> Database

Opérateurs T-SQL SET Partie 2 :INTERSECT et EXCEPT

Dans mon article précédent, j'ai expliqué les bases des opérateurs d'ensemble, leurs types et les conditions préalables à leur utilisation. J'ai également parlé des opérateurs UNION et UNION ALL, de leur utilisation et de leurs différences.

Dans cet article, nous allons apprendre ce qui suit :

  1. Opérateurs EXCEPT et INTERSECT.
  2. Différence entre INTERSECT et INNER JOIN.
  3. L'explication détaillée de INTERSECT et EXCEPT avec un exemple.

Les opérateurs EXCEPT et INTERSECT ont été introduits dans SQL Server 2005. Les deux sont des opérateurs d'ensemble utilisés pour combiner les ensembles de résultats générés par deux requêtes et récupérer la sortie souhaitée.

Qu'est-ce que l'opérateur INTERSECT ?

INTERSECT est utilisé pour obtenir des enregistrements communs à tous les ensembles de données extraits de plusieurs requêtes ou tables. En voici une visualisation :

La syntaxe de l'opérateur INTERSECT est la suivante :

SELECT COLUMN1, 
       COLUMN2, 
       COLUMN3, 
       COLUMN4..FROM TABLE1 
INTERSECT
SELECT COLUMN1, 
       COLUMN2, 
       COLUMN3, 
       COLUMN4..FROM TABLE2

Qu'est-ce que l'opérateur EXCEPT

EXCEPT est utilisé pour récupérer des enregistrements trouvés dans une requête mais pas dans une autre requête. En d'autres termes, il renvoie des enregistrements qui sont uniques à un ensemble de résultats. Voici à quoi cela ressemble visualisé :

La syntaxe de l'opérateur SAUF est la suivante :

SELECT COLUMN1, 
       COLUMN2, 
       COLUMN3, 
       COLUMN4..FROM TABLE1 
EXCEPT
SELECT COLUMN1, 
       COLUMN2, 
       COLUMN3, 
       COLUMN4..FROM TABLE2

Créons une configuration de démonstration pour montrer comment ces opérateurs peuvent être utilisés.

Configuration de la démo

Pour démontrer INTERSECT et EXCEPT, j'ai créé deux tables nommées Employee et Stagiaire .

Exécutez la requête suivante pour créer ces tables :

CREATE TABLE [DBO].[EMPLOYEE] 
  ( 
     [NAME]             [NVARCHAR](250) NOT NULL, 
     [BUSINESSENTITYID] [INT] NOT NULL, 
     [NATIONALIDNUMBER] [NVARCHAR](15) NOT NULL, 
     [LOGINID]          [NVARCHAR](256) NOT NULL, 
     [BIRTHDATE]        [DATE] NOT NULL, 
     [MARITALSTATUS]    [NCHAR](1) NOT NULL, 
     [GENDER]           [NCHAR](1) NOT NULL 
  ) 
ON [PRIMARY] 

CREATE TABLE [DBO].[TRAINEE] 
  ( 
     [NAME]             [NVARCHAR](250) NOT NULL, 
     [BUSINESSENTITYID] [INT] NOT NULL, 
     [NATIONALIDNUMBER] [NVARCHAR](15) NOT NULL, 
     [BIRTHDATE]        [DATE] NOT NULL, 
     [GENDER]           [NCHAR](1) NOT NULL 
  ) 
ON [PRIMARY]

Maintenant, insérons des données factices dans le champ Employé table en exécutant la requête suivante :

INSERT [DBO].[EMPLOYEE] ([NAME], [BUSINESSENTITYID], [NATIONALIDNUMBER], [LOGINID], [BIRTHDATE], [MARITALSTATUS], [GENDER]) VALUES (N'KEN SÁNCHEZ', 1, N'295847284', N'ADVENTURE-WORKS\KEN0', CAST(N'1969-01-29' AS DATE), N'S', N'M')
GO
INSERT [DBO].[EMPLOYEE] ([NAME], [BUSINESSENTITYID], [NATIONALIDNUMBER], [LOGINID], [BIRTHDATE], [MARITALSTATUS], [GENDER]) VALUES (N'TERRI DUFFY', 2, N'245797967', N'ADVENTURE-WORKS\TERRI0', CAST(N'1971-08-01' AS DATE), N'S', N'F')
GO
INSERT [DBO].[EMPLOYEE] ([NAME], [BUSINESSENTITYID], [NATIONALIDNUMBER], [LOGINID], [BIRTHDATE], [MARITALSTATUS], [GENDER]) VALUES (N'ROBERTO TAMBURELLO', 3, N'509647174', N'ADVENTURE-WORKS\ROBERTO0', CAST(N'1974-11-12' AS DATE), N'M', N'M')
GO
INSERT [DBO].[EMPLOYEE] ([NAME], [BUSINESSENTITYID], [NATIONALIDNUMBER], [LOGINID], [BIRTHDATE], [MARITALSTATUS], [GENDER]) VALUES (N'ROB WALTERS', 4, N'112457891', N'ADVENTURE-WORKS\ROB0', CAST(N'1974-12-23' AS DATE), N'S', N'M')
GO
INSERT [DBO].[EMPLOYEE] ([NAME], [BUSINESSENTITYID], [NATIONALIDNUMBER], [LOGINID], [BIRTHDATE], [MARITALSTATUS], [GENDER]) VALUES (N'GAIL ERICKSON', 5, N'695256908', N'ADVENTURE-WORKS\GAIL0', CAST(N'1952-09-27' AS DATE), N'M', N'F')
GO
INSERT [DBO].[EMPLOYEE] ([NAME], [BUSINESSENTITYID], [NATIONALIDNUMBER], [LOGINID], [BIRTHDATE], [MARITALSTATUS], [GENDER]) VALUES (N'JOSSEF GOLDBERG', 6, N'998320692', N'ADVENTURE-WORKS\JOSSEF0', CAST(N'1959-03-11' AS DATE), N'M', N'M')

Ensuite, nous ferons la même chose pour le Stagiaire tableau :

INSERT [DBO].[TRAINEE] ([NAME], [BUSINESSENTITYID], [NATIONALIDNUMBER], [BIRTHDATE], [GENDER]) VALUES (N'JOHN WOOD', 18, N'222969461', CAST(N'1978-03-06' AS DATE), N'M')
GO
INSERT [DBO].[TRAINEE] ([NAME], [BUSINESSENTITYID], [NATIONALIDNUMBER], [BIRTHDATE], [GENDER]) VALUES (N'MARY DEMPSEY', 19, N'52541318', CAST(N'1978-01-29' AS DATE), N'F')
GO
INSERT [DBO].[TRAINEE] ([NAME], [BUSINESSENTITYID], [NATIONALIDNUMBER], [BIRTHDATE], [GENDER]) VALUES (N'WANIDA BENSHOOF', 20, N'323403273', CAST(N'1975-03-17' AS DATE), N'F')
GO
INSERT [DBO].[TRAINEE] ([NAME], [BUSINESSENTITYID], [NATIONALIDNUMBER], [BIRTHDATE], [GENDER]) VALUES (N'KEN SÁNCHEZ', 1, N'295847284', CAST(N'1969-01-29' AS DATE), N'M')
GO
INSERT [DBO].[TRAINEE] ([NAME], [BUSINESSENTITYID], [NATIONALIDNUMBER], [BIRTHDATE], [GENDER]) VALUES (N'TERRI DUFFY', 2, N'245797967', CAST(N'1971-08-01' AS DATE),  N'F')
GO
INSERT [DBO].[TRAINEE] ([NAME], [BUSINESSENTITYID], [NATIONALIDNUMBER], [BIRTHDATE], [GENDER]) VALUES (N'ROBERTO TAMBURELLO', 3, N'509647174', CAST(N'1974-11-12' AS DATE), N'M')
GO

Maintenant, utilisons INTERSECT pour récupérer la liste des employés communs aux deux tables. Pour ce faire, exécutez la requête suivante :

SELECT NAME, 
       BUSINESSENTITYID, 
       NATIONALIDNUMBER, 
       BIRTHDATE, 
       GENDER 
FROM   EMPLOYEE 
INTERSECT 
SELECT NAME, 
       BUSINESSENTITYID, 
       NATIONALIDNUMBER, 
       BIRTHDATE, 
       GENDER 
FROM   TRAINEE

Le résultat de cette requête devrait être le suivant :

Comme vous pouvez le voir dans la capture d'écran ci-dessus, la requête n'a renvoyé que des enregistrements communs aux deux tables.

INNER JOIN vs. INTERSECT

Dans la plupart des cas, INTERSECT et INNER JOIN renvoient la même sortie, mais il existe quelques exceptions. Un exemple simple nous aidera à comprendre cela.

Ajoutons quelques enregistrements en double à la table Trainee. Exécutez la requête suivante :

INSERT [DBO].[TRAINEE] ([NAME], [BUSINESSENTITYID], [NATIONALIDNUMBER], [BIRTHDATE], [GENDER]) VALUES (N'TERRI DUFFY', 2, N'245797967', CAST(N'1971-08-01' AS DATE),  N'F')
GO
INSERT [DBO].[TRAINEE] ([NAME], [BUSINESSENTITYID], [NATIONALIDNUMBER], [BIRTHDATE], [GENDER]) VALUES (N'ROBERTO TAMBURELLO', 3, N'509647174', CAST(N'1974-11-12' AS DATE), N'M')
GO

Maintenant, nous allons essayer de générer la sortie souhaitée en utilisant INTERSECT.

SELECT NAME,BUSINESSENTITYID,NATIONALIDNUMBER,BIRTHDATE,GENDER FROM EMPLOYEE
INTERSECT
SELECT NAME,BUSINESSENTITYID,NATIONALIDNUMBER,BIRTHDATE,GENDER FROM TRAINEE

Voici la sortie que nous obtenons :

Maintenant, essayons d'utiliser INNER JOIN.

SELECT A.NAME, 
       A.BUSINESSENTITYID, 
       A.NATIONALIDNUMBER, 
       A.BIRTHDATE, 
       A.GENDER 
FROM   EMPLOYEE A 
       INNER JOIN TRAINEE B 
               ON A.NAME = B.NAME

La sortie que nous obtenons dans ce cas est la suivante :

Maintenant, comme vous pouvez le voir sur la capture d'écran ci-dessus, INNER JOIN récupère les enregistrements communs aux deux tables. Il remplit tous les enregistrements de la table de droite. Par conséquent, vous pouvez voir les enregistrements en double.

Maintenant, ajoutons le mot-clé DISTINCT à la requête INNER JOIN et regardons ce que cela fait :

SELECT DISTINCT A.NAME, 
                A.BUSINESSENTITYID, 
                A.NATIONALIDNUMBER, 
                A.BIRTHDATE, 
                A.GENDER 
FROM   EMPLOYEE A 
       INNER JOIN TRAINEE B 
               ON A.NAME = B.NAME

Le résultat devrait ressembler à ceci :

Comme vous pouvez le voir sur la capture d'écran ci-dessus, les enregistrements en double ont été éliminés.

INTERSECT et INNER JOIN traitent les valeurs NULL différemment. Pour INNER JOIN, deux valeurs NULL sont différentes, il y a donc des chances qu'il les ignore lors de la jointure de deux tables.

D'autre part, INTERSECT traite deux valeurs NULL comme étant identiques, de sorte que les enregistrements qui ont des valeurs NULL ne seront pas éliminés. Pour mieux comprendre, regardons un exemple.

Tout d'abord, ajoutons quelques valeurs NULL au Trainee et Employé tables en exécutant la requête suivante :

INSERT [DBO].[TRAINEE] ([NAME], [BUSINESSENTITYID], [NATIONALIDNUMBER], [BIRTHDATE], [GENDER]) VALUES (NULL, 3, N'509647174', CAST(N'1974-11-12' AS DATE), N'M')
GO

INSERT [DBO].[Employee] ([NAME], [BUSINESSENTITYID], [NATIONALIDNUMBER],[LOGINID], [BIRTHDATE],[MARITALSTATUS], [GENDER]) VALUES (NULL, 3, N'509647174','ADVENTURE-WORKS\TERRI0', CAST(N'1974-11-12' AS DATE),  N'M',N'M')
GO

Essayons maintenant de récupérer les enregistrements communs aux deux tables en utilisant INTERSECT et INNER JOIN. Vous devrez exécuter la requête suivante :

/*QUERY WITH INTERSECT*/ 
SELECT NAME, 
       BUSINESSENTITYID, 
       NATIONALIDNUMBER, 
       BIRTHDATE, 
       GENDER 
FROM   EMPLOYEE 
INTERSECT 
SELECT NAME, 
       BUSINESSENTITYID, 
       NATIONALIDNUMBER, 
       BIRTHDATE, 
       GENDER 
FROM   TRAINEE 

/*QUERY WITH INNER JOIN*/ 
SELECT A.NAME, 
       A.BUSINESSENTITYID, 
       A.NATIONALIDNUMBER, 
       A.BIRTHDATE, 
       A.GENDER 
FROM   EMPLOYEE A 
       INNER JOIN TRAINEE B 
               ON A.NAME = B.NAME

Voici le résultat que nous devrions obtenir :

Comme vous pouvez le voir ci-dessus, le jeu de résultats généré par INTERSECT contient des valeurs NULL, tandis que INNER JOIN a ignoré les enregistrements contenant des valeurs NULL.

L'opérateur SAUF

Pour démontrer l'opérateur EXCEPT en action, examinons un cas d'utilisation. Par exemple, je veux remplir les détails des employées de la table Employee. La requête suivante nous aidera à faire exactement cela :

SELECT NAME, 
       BUSINESSENTITYID, 
       NATIONALIDNUMBER, 
       BIRTHDATE, 
       GENDER 
FROM   EMPLOYEE 
WHERE  GENDER = 'F' 
EXCEPT 
SELECT NAME, 
       BUSINESSENTITYID, 
       NATIONALIDNUMBER, 
       BIRTHDATE, 
       GENDER 
FROM   EMPLOYEE 
WHERE  GENDER = 'M'

Voici la sortie que nous obtenons :

Comme vous pouvez le voir ci-dessus, la requête n'a rempli que les détails des employées.

Vous pouvez également remplir le jeu de résultats à l'aide d'une sous-requête :

SELECT NAME, 
       BUSINESSENTITYID, 
       NATIONALIDNUMBER, 
       BIRTHDATE, 
       GENDER 
FROM   EMPLOYEE AS M 
WHERE  GENDER = 'F' 
       AND GENDER NOT IN (SELECT GENDER 
                          FROM   EMPLOYEE AS F 
                          WHERE  GENDER = 'M')

Limites d'INTERSECT et EXCEPT

  1. Nous ne pouvons pas utiliser EXCEPT et INTERSECT dans les définitions de vues partitionnées distribuées avec les clauses COMPUTE et COMPUTE BY.
  2. EXCEPT et INTERSECT peuvent être utilisés dans les curseurs d'avance rapide uniquement et statiques.
  3. EXCEPT et INTERSECT peuvent être utilisés dans des requêtes distribuées, mais ne peuvent être exécutés que sur le serveur local. Vous ne pouvez pas les exécuter sur un serveur distant.

Résumé

Dans cet article, j'ai couvert :

  1. Les opérateurs EXCEPT et INTERSECT.
  2. La différence entre INTERSECT et INNER JOIN.
  3. Une explication détaillée des opérateurs INTERSECT et EXCEPT avec un exemple.