Database
 sql >> Database >  >> RDS >> Database

Operatori T-SQL SET Parte 2:INTERSECT e EXCEPT

Nel mio precedente articolo ho spiegato le basi degli operatori di insiemi, i loro tipi e i prerequisiti per il loro utilizzo. Ho anche parlato degli operatori UNION e UNION ALL, del loro utilizzo e delle loro differenze.

In questo articolo impareremo quanto segue:

  1. Operatori EXCEPT e INTERSECT.
  2. Differenza tra INTERSECT e INNER JOIN.
  3. La spiegazione dettagliata di INTERSECT e EXCEPT con un esempio.

Gli operatori EXCEPT e INTERSECT sono stati introdotti in SQL Server 2005. Entrambi sono operatori di insiemi utilizzati per combinare i set di risultati generati da due query e recuperare l'output desiderato.

Cos'è l'operatore INTERSECT

INTERSECT viene utilizzato per ottenere record comuni a tutti i set di dati recuperati da più query o tabelle. Ecco una visualizzazione di questo:

La sintassi dell'operatore INTERSECT è la seguente:

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

Cos'è l'operatore EXCEPT

EXCEPT viene utilizzato per recuperare i record che si trovano in una query ma non in un'altra query. In altre parole, restituisce record che sono univoci per un set di risultati. Ecco come appare visualizzato:

La sintassi dell'operatore EXCEPT è la seguente:

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

Creiamo una configurazione demo per dimostrare come utilizzare questi operatori.

Configurazione demo

Per dimostrare INTERSECT ed EXCEPT, ho creato due tabelle denominate Employee e Tirocinante .

Esegui la seguente query per creare queste tabelle:

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]

Ora inseriamo alcuni dati fittizi nel Dipendente tabella eseguendo la query seguente:

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')

Successivamente, faremo la stessa cosa per il Tirocinante tabella:

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

Ora, utilizziamo INTERSECT per recuperare l'elenco dei dipendenti che sono comuni a entrambe le tabelle. Per farlo, esegui la seguente query:

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

L'output di questa query dovrebbe essere il seguente:

Come puoi vedere nello screenshot qui sopra, la query ha restituito solo record comuni a entrambe le tabelle.

INNER JOIN vs. INTERSECT

Nella maggior parte dei casi, INTERSECT e INNER JOIN restituiscono lo stesso output, ma ci sono alcune eccezioni. Un semplice esempio ci aiuterà a capirlo.

Aggiungiamo alcuni record duplicati alla tabella Allievo. Esegui la seguente query:

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

Ora proveremo a generare l'output desiderato utilizzando INTERSECT.

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

Questo è l'output che otteniamo:

Ora, proviamo a utilizzare 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

L'output che otteniamo in questo caso è il seguente:

Ora, come puoi vedere nello screenshot sopra, INNER JOIN recupera i record che sono comuni a entrambe le tabelle. Popola tutti i record dalla tabella giusta. Pertanto, puoi vedere record duplicati.

Ora aggiungiamo la parola chiave DISTINCT alla query INNER JOIN e vediamo cosa fa:

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

L'output dovrebbe essere simile a questo:

Come puoi vedere nello screenshot qui sopra, i record duplicati sono stati eliminati.

INTERSECT e INNER JOIN trattano i valori NULL in modo diverso. Per INNER JOIN, due valori NULL sono diversi, quindi è possibile che li salti durante l'unione di due tabelle.

D'altra parte, INTERSECT tratta due valori NULL come uguali, quindi i record che hanno valori NULL non verranno eliminati. Per capirlo meglio, diamo un'occhiata a un esempio.

Innanzitutto, aggiungiamo alcuni valori NULL al Tirocinante e Dipendente tabelle eseguendo la query seguente:

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

Proviamo ora a recuperare i record comuni alle due tabelle utilizzando INTERSECT e INNER JOIN. Dovrai eseguire la seguente query:

/*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

Questo è l'output che dovremmo ottenere come risultato:

Come puoi vedere sopra, il set di risultati generato da INTERSECT contiene valori NULL, mentre INNER JOIN ha saltato i record che hanno valori NULL.

L'operatore EXCEPT

Per dimostrare l'operatore EXCEPT in azione, diamo un'occhiata a un caso d'uso. Ad esempio, voglio popolare i dettagli delle dipendenti di sesso femminile dalla tabella Dipendente. La seguente query ci aiuterà a fare proprio questo:

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

Questo è l'output che otteniamo:

Come puoi vedere sopra, la query ha popolato solo i dettagli delle dipendenti di sesso femminile.

Puoi anche popolare il set di risultati utilizzando una sottoquery:

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')

Limitazioni di INTERSECT e EXCEPT

  1. Non possiamo utilizzare EXCEPT e INTERSECT nelle definizioni di viste partizionate distribuite con le clausole COMPUTE e COMPUTE BY.
  2. EXCEPT e INTERSECT possono essere utilizzati nei cursori statici e di solo avanzamento rapido.
  3. EXCEPT e INTERSECT possono essere utilizzati nelle query distribuite, ma possono essere eseguiti solo sul server locale. Non puoi eseguirli su un server remoto.

Riepilogo

In questo articolo ho trattato:

  1. Gli operatori EXCEPT e INTERSECT.
  2. La differenza tra INTERSECT e INNER JOIN.
  3. Una spiegazione dettagliata degli operatori INTERSECT e EXCEPT con un esempio.