I min tidligere artikel forklarede jeg det grundlæggende om sætoperatører, deres typer og forudsætninger for deres brug. Jeg talte også om UNION og UNION ALL operatører, deres brug og forskelle.
I denne artikel skal vi lære følgende:
- EXCEPT og INTERSECT-operatorer.
- Forskel mellem INTERSECT og INNER JOIN.
- Den detaljerede forklaring af INTERSECT og EXCEPT med et eksempel.
EXCEPT- og INTERSECT-operatorer blev introduceret i SQL Server 2005. Begge er sæt-operatorer, der bruges til at kombinere resultatsæt genereret af to forespørgsler og hente det ønskede output.
Hvad er INTERSECT-operatøren
INTERSECT bruges til at få poster, der er fælles for alle datasæt, hentet fra flere forespørgsler eller tabeller. Her er en visualisering af dette:
Syntaksen for INTERSECT-operatoren er som følger:
SELECT COLUMN1, COLUMN2, COLUMN3, COLUMN4..FROM TABLE1 INTERSECT SELECT COLUMN1, COLUMN2, COLUMN3, COLUMN4..FROM TABLE2
Hvad er EXCEPT-operatøren
EXCEPT bruges til at hente poster, som findes i én forespørgsel, men ikke i en anden forespørgsel. Med andre ord returnerer den poster, som er unikke for ét resultatsæt. Sådan ser det ud visualiseret:
Syntaksen for operatoren EXCEPT er som følger:
SELECT COLUMN1, COLUMN2, COLUMN3, COLUMN4..FROM TABLE1 EXCEPT SELECT COLUMN1, COLUMN2, COLUMN3, COLUMN4..FROM TABLE2
Lad os lave en demo-opsætning for at demonstrere, hvordan disse operatører kan bruges.
Demoopsætning
For at demonstrere INTERSECT og EXCEPT oprettede jeg to tabeller med navnet Medarbejder og elev .
Kør følgende forespørgsel for at oprette disse tabeller:
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]
Lad os nu indsætte nogle dummy-data i medarbejderen tabel ved at udføre følgende forespørgsel:
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')
Dernæst vil vi gøre det samme for praktikanten tabel:
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
Lad os nu bruge INTERSECT til at hente listen over medarbejdere, der er fælles for begge tabeller. For at gøre det skal du køre følgende forespørgsel:
SELECT NAME, BUSINESSENTITYID, NATIONALIDNUMBER, BIRTHDATE, GENDER FROM EMPLOYEE INTERSECT SELECT NAME, BUSINESSENTITYID, NATIONALIDNUMBER, BIRTHDATE, GENDER FROM TRAINEE
Outputtet af denne forespørgsel skal være som følger:
Som du kan se på skærmbilledet ovenfor, har forespørgslen kun returneret poster, som er fælles for begge tabeller.
INNER JOIN vs. INTERSECT
I de fleste tilfælde returnerer INTERSECT og INNER JOIN det samme output, men der er nogle undtagelser. Et simpelt eksempel vil hjælpe os med at forstå dette.
Lad os tilføje nogle duplikerede poster til Trainee-tabellen. Udfør følgende forespørgsel:
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
Nu vil vi forsøge at generere det ønskede output ved hjælp af INTERSECT.
SELECT NAME,BUSINESSENTITYID,NATIONALIDNUMBER,BIRTHDATE,GENDER FROM EMPLOYEE INTERSECT SELECT NAME,BUSINESSENTITYID,NATIONALIDNUMBER,BIRTHDATE,GENDER FROM TRAINEE
Dette er det output, vi får:
Lad os nu prøve at bruge 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
Det output, vi får i dette tilfælde, er som følger:
Nu, som du kan se på skærmbilledet ovenfor, henter INNER JOIN poster, som er fælles for begge tabeller. Den udfylder alle poster fra den højre tabel. Derfor kan du se duplikerede poster.
Lad os nu tilføje DISTINCT søgeordet til INNER JOIN-forespørgslen og se på, hvad dette gør:
SELECT DISTINCT A.NAME, A.BUSINESSENTITYID, A.NATIONALIDNUMBER, A.BIRTHDATE, A.GENDER FROM EMPLOYEE A INNER JOIN TRAINEE B ON A.NAME = B.NAME
Outputtet skal se sådan ud:
Som du kan se på skærmbilledet ovenfor, er duplikerede poster blevet elimineret.
INTERSECT og INNER JOIN behandler NULL-værdier forskelligt. For INNER JOIN er to NULL-værdier forskellige, så der er chancer for, at den springer dem over, mens de forbinder to tabeller.
På den anden side behandler INTERSECT to NULL-værdier som værende ens, så poster, der har NULL-værdier, vil ikke blive elimineret. For at forstå det bedre, lad os se på et eksempel.
Lad os først tilføje nogle NULL-værdier til Trainee og medarbejder tabeller ved at udføre følgende forespørgsel:
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
Lad os nu prøve at hente poster, der er fælles for de to tabeller, ved hjælp af INTERSECT og INNER JOIN. Du skal udføre følgende forespørgsel:
/*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
Dette er det output, vi bør få som et resultat:
Som du kan se ovenfor, indeholder resultatsættet genereret af INTERSECT NULL-værdier, mens INNER JOIN sprang de poster over, der har NULL-værdier.
UNDTAGET operatøren
For at demonstrere EXCEPT-operatøren i aktion, lad os se på en use case. For eksempel vil jeg udfylde oplysningerne om kvindelige medarbejdere fra tabellen medarbejder. Følgende forespørgsel hjælper os med at gøre netop det:
SELECT NAME, BUSINESSENTITYID, NATIONALIDNUMBER, BIRTHDATE, GENDER FROM EMPLOYEE WHERE GENDER = 'F' EXCEPT SELECT NAME, BUSINESSENTITYID, NATIONALIDNUMBER, BIRTHDATE, GENDER FROM EMPLOYEE WHERE GENDER = 'M'
Dette er det output, vi får:
Som du kan se ovenfor, udfyldte forespørgslen kun de kvindelige medarbejderes oplysninger.
Du kan også udfylde resultatsættet ved hjælp af en underforespørgsel:
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')
Begrænsninger for INTERSECT og EXCEPT
- Vi kan ikke bruge EXCEPT og INTERSECT i distribuerede partitionerede visningsdefinitioner med COMPUTE- og COMPUTE BY-sætninger.
- EXCEPT og INTERSECT kan bruges i fast forward-kun og statiske markører.
- EXCEPT og INTERSECT kan bruges i distribuerede forespørgsler, men kan kun udføres på den lokale server. Du kan ikke køre dem på en ekstern server.
Oversigt
I denne artikel har jeg dækket:
- EXCEPT- og INTERSECT-operatørerne.
- Forskellen mellem INTERSECT og INNER JOIN.
- En detaljeret forklaring af operatorerne INTERSECT og EXCEPT med et eksempel.