W moim poprzednim artykule wyjaśniłem podstawy operatorów mnogościowych, ich typy i warunki ich użycia. Mówiłem również o operatorach UNION i UNION ALL, ich zastosowaniu i różnicach.
W tym artykule dowiemy się, co następuje:
- Operatory EXCEPT i INTERSECT.
- Różnica między INTERSECT i INNER JOIN.
- Szczegółowe objaśnienie INTERSECT i Z WYJĄTKIEM przykładu.
Operatory EXCEPT i INTERSECT zostały wprowadzone w SQL Server 2005. Oba są operatorami zestawów używanymi do łączenia zestawów wyników wygenerowanych przez dwa zapytania i pobierania żądanego wyniku.
Co to jest operator INTERSECT
INTERSECT służy do pobierania rekordów wspólnych dla wszystkich zestawów danych pobranych z wielu zapytań lub tabel. Oto wizualizacja tego:
Składnia operatora INTERSECT jest następująca:
SELECT COLUMN1, COLUMN2, COLUMN3, COLUMN4..FROM TABLE1 INTERSECT SELECT COLUMN1, COLUMN2, COLUMN3, COLUMN4..FROM TABLE2
Co to jest operator Z WYJĄTKIEM
Z WYJĄTKIEM służy do pobierania rekordów znalezionych w jednym zapytaniu, ale nie w innym zapytaniu. Innymi słowy, zwraca rekordy, które są unikalne dla jednego zestawu wyników. Tak to wygląda na wizualizacji:
Składnia operatora EXCEPT jest następująca:
SELECT COLUMN1, COLUMN2, COLUMN3, COLUMN4..FROM TABLE1 EXCEPT SELECT COLUMN1, COLUMN2, COLUMN3, COLUMN4..FROM TABLE2
Stwórzmy konfigurację demonstracyjną, aby zademonstrować, jak można używać tych operatorów.
Konfiguracja wersji demonstracyjnej
Aby zademonstrować INTERSECT i EXCEPT, utworzyłem dwie tabele o nazwie Pracownik i Praktykant .
Wykonaj następujące zapytanie, aby utworzyć te tabele:
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]
Teraz wstawmy kilka fikcyjnych danych do Pracownika tabeli, wykonując następujące zapytanie:
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')
Następnie zrobimy to samo dla stażysty tabela:
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
Teraz użyjmy INTERSECT, aby pobrać listę pracowników wspólnych dla obu tabel. Aby to zrobić, uruchom następujące zapytanie:
SELECT NAME, BUSINESSENTITYID, NATIONALIDNUMBER, BIRTHDATE, GENDER FROM EMPLOYEE INTERSECT SELECT NAME, BUSINESSENTITYID, NATIONALIDNUMBER, BIRTHDATE, GENDER FROM TRAINEE
Wynik tego zapytania powinien wyglądać następująco:
Jak widać na powyższym zrzucie ekranu, zapytanie zwróciło tylko rekordy, które są wspólne dla obu tabel.
ZŁĄCZENIE WEWNĘTRZNE a PRZECIĘCIE
W większości przypadków INTERSECT i INNER JOIN zwracają te same dane wyjściowe, ale są pewne wyjątki. Prosty przykład pomoże nam to zrozumieć.
Dodajmy kilka zduplikowanych rekordów do tabeli Trainee. Wykonaj następujące zapytanie:
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
Teraz spróbujemy wygenerować żądany wynik za pomocą INTERSECT.
SELECT NAME,BUSINESSENTITYID,NATIONALIDNUMBER,BIRTHDATE,GENDER FROM EMPLOYEE INTERSECT SELECT NAME,BUSINESSENTITYID,NATIONALIDNUMBER,BIRTHDATE,GENDER FROM TRAINEE
Oto wynik, który otrzymujemy:
Teraz spróbujmy użyć 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
Wynik jaki otrzymujemy w tym przypadku jest następujący:
Teraz, jak widać na powyższym zrzucie ekranu, INNER JOIN pobiera rekordy, które są wspólne dla obu tabel. Wypełnia wszystkie rekordy z prawej tabeli. Dlatego możesz zobaczyć zduplikowane rekordy.
Teraz dodajmy słowo kluczowe DISTINCT do zapytania INNER JOIN i zobaczmy, co to daje:
SELECT DISTINCT A.NAME, A.BUSINESSENTITYID, A.NATIONALIDNUMBER, A.BIRTHDATE, A.GENDER FROM EMPLOYEE A INNER JOIN TRAINEE B ON A.NAME = B.NAME
Wynik powinien wyglądać tak:
Jak widać na powyższym zrzucie ekranu, zduplikowane rekordy zostały wyeliminowane.
INTERSECT i INNER JOIN traktują wartości NULL inaczej. W przypadku INNER JOIN dwie wartości NULL są różne, więc istnieje prawdopodobieństwo, że pominie je podczas dołączania do dwóch stołów.
Z drugiej strony, INTERSECT traktuje dwie wartości NULL jako takie same, więc rekordy, które mają wartości NULL, nie zostaną wyeliminowane. Aby lepiej to zrozumieć, spójrzmy na przykład.
Najpierw dodajmy kilka wartości NULL do Stażysty i Pracownik tabele, wykonując następujące zapytanie:
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
Teraz spróbujmy pobrać rekordy wspólne dla dwóch tabel za pomocą INTERSECT i INNER JOIN. Musisz wykonać następujące zapytanie:
/*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
Oto wynik, który powinniśmy otrzymać w rezultacie:
Jak widać powyżej, zestaw wyników wygenerowany przez INTERSECT zawiera wartości NULL, podczas gdy INNER JOIN pominął rekordy, które mają wartości NULL.
Z WYJĄTKIEM operatora
Aby zademonstrować działanie operatora EXCEPT, spójrzmy na przypadek użycia. Na przykład chcę wypełnić dane pracownic z tabeli Pracownik. Pomoże nam w tym następujące zapytanie:
SELECT NAME, BUSINESSENTITYID, NATIONALIDNUMBER, BIRTHDATE, GENDER FROM EMPLOYEE WHERE GENDER = 'F' EXCEPT SELECT NAME, BUSINESSENTITYID, NATIONALIDNUMBER, BIRTHDATE, GENDER FROM EMPLOYEE WHERE GENDER = 'M'
Oto wynik, który otrzymujemy:
Jak widać powyżej, zapytanie zawierało tylko dane pracownic.
Możesz również wypełnić zestaw wyników za pomocą podzapytania:
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')
Ograniczenia INTERSECT i Z WYJĄTKIEM
- Nie możemy używać EXCEPT i INTERSECT w definicjach rozproszonych widoków partycjonowanych z klauzulami COMPUTE i COMPUTE BY.
- EXCEPT i INTERSECT mogą być używane w kursorach tylko do szybkiego przewijania do przodu i statycznych.
- EXCEPT i INTERSECT mogą być używane w zapytaniach rozproszonych, ale mogą być wykonywane tylko na serwerze lokalnym. Nie możesz ich uruchomić na zdalnym serwerze.
Podsumowanie
W tym artykule omówiłem:
- Operatory EXCEPT i INTERSECT.
- Różnica między INTERSECT i INNER JOIN.
- Szczegółowe wyjaśnienie operatorów INTERSECT i EXCEPT z przykładem.