前回の記事では、set演算子の基本、それらのタイプ、およびそれらを使用するための前提条件について説明しました。 UNIONとUNIONALLの演算子、それらの使用法と違いについても話しました。
この記事では、次のことを学びます。
- EXCEPTおよびINTERSECT演算子。
- INTERSECTとINNERJOINの違い。
- INTERSECTとEXCEPTの詳細な説明と例。
EXCEPT演算子とINTERSECT演算子は、SQL Server 2005で導入されました。どちらも、2つのクエリによって生成された結果セットを結合し、目的の出力を取得するために使用される集合演算子です。
INTERSECT演算子とは
INTERSECTは、複数のクエリまたはテーブルから取得されたすべてのデータセットに共通のレコードを取得するために使用されます。これを視覚化したものは次のとおりです。
INTERSECT演算子の構文は次のとおりです。
SELECT COLUMN1, COLUMN2, COLUMN3, COLUMN4..FROM TABLE1 INTERSECT SELECT COLUMN1, COLUMN2, COLUMN3, COLUMN4..FROM TABLE2
EXCEPT演算子とは
EXCEPTは、あるクエリでは検出されたが別のクエリでは検出されなかったレコードを取得するために使用されます。つまり、1つの結果セットに固有のレコードを返します。これは視覚化されたように見えます:
EXCEPT演算子の構文は次のとおりです。
SELECT COLUMN1, COLUMN2, COLUMN3, COLUMN4..FROM TABLE1 EXCEPT SELECT COLUMN1, COLUMN2, COLUMN3, COLUMN4..FROM TABLE2
これらの演算子の使用方法を示すデモセットアップを作成しましょう。
デモのセットアップ
INTERSECTとEXCEPTを示すために、 Employeeという名前の2つのテーブルを作成しました。 および研修生 。
次のクエリを実行して、これらのテーブルを作成します:
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]
それでは、ダミーデータを従業員に挿入しましょう。 次のクエリを実行してテーブルを作成します:
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')
次に、研修生についても同じことを行います テーブル:
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
それでは、INTERSECTを使用して、両方のテーブルに共通する従業員のリストを取得しましょう。これを行うには、次のクエリを実行します。
SELECT NAME, BUSINESSENTITYID, NATIONALIDNUMBER, BIRTHDATE, GENDER FROM EMPLOYEE INTERSECT SELECT NAME, BUSINESSENTITYID, NATIONALIDNUMBER, BIRTHDATE, GENDER FROM TRAINEE
このクエリの出力は次のようになります。
上のスクリーンショットでわかるように、クエリは両方のテーブルに共通のレコードのみを返しました。
内部結合と交差
ほとんどの場合、INTERSECTとINNER JOINは同じ出力を返しますが、いくつかの例外があります。簡単な例は、これを理解するのに役立ちます。
重複するレコードをTraineeテーブルに追加しましょう。次のクエリを実行します:
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
次に、INTERSECTを使用して目的の出力を生成しようとします。
SELECT NAME,BUSINESSENTITYID,NATIONALIDNUMBER,BIRTHDATE,GENDER FROM EMPLOYEE INTERSECT SELECT NAME,BUSINESSENTITYID,NATIONALIDNUMBER,BIRTHDATE,GENDER FROM TRAINEE
これが私たちが得る出力です:
それでは、INNERJOINを使ってみましょう。
SELECT A.NAME, A.BUSINESSENTITYID, A.NATIONALIDNUMBER, A.BIRTHDATE, A.GENDER FROM EMPLOYEE A INNER JOIN TRAINEE B ON A.NAME = B.NAME
この場合の出力は次のとおりです。
これで、上のスクリーンショットでわかるように、INNERJOINは両方のテーブルに共通のレコードを取得します。右側のテーブルからすべてのレコードにデータを入力します。したがって、重複したレコードが表示される可能性があります。
それでは、DISTINCTキーワードをINNER JOINクエリに追加して、これが何をするかを見てみましょう。
SELECT DISTINCT A.NAME, A.BUSINESSENTITYID, A.NATIONALIDNUMBER, A.BIRTHDATE, A.GENDER FROM EMPLOYEE A INNER JOIN TRAINEE B ON A.NAME = B.NAME
出力は次のようになります。
上のスクリーンショットでわかるように、重複するレコードは削除されています。
INTERSECTとINNERJOINは、NULL値を異なる方法で処理します。 INNER JOINの場合、2つのNULL値が異なるため、2つのテーブルを結合するときにそれらをスキップする可能性があります。
一方、INTERSECTは2つのNULL値を同じものとして扱うため、NULL値を持つレコードは削除されません。それをよりよく理解するために、例を見てみましょう。
まず、研修生にNULL値を追加しましょう および従業員 次のクエリを実行してテーブルを作成します:
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
次に、INTERSECTとINNER JOINを使用して、2つのテーブルに共通するレコードを取得してみましょう。次のクエリを実行する必要があります:
/*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
結果として得られるはずの出力は次のとおりです。
上記のように、INTERSECTによって生成された結果セットにはNULL値が含まれていますが、INNERJOINはNULL値を持つレコードをスキップしました。
EXCEPTオペレーター
EXCEPT演算子の動作を示すために、ユースケースを見てみましょう。たとえば、Employeeテーブルから女性従業員の詳細を入力したいとします。次のクエリは、まさにそれを行うのに役立ちます:
SELECT NAME, BUSINESSENTITYID, NATIONALIDNUMBER, BIRTHDATE, GENDER FROM EMPLOYEE WHERE GENDER = 'F' EXCEPT SELECT NAME, BUSINESSENTITYID, NATIONALIDNUMBER, BIRTHDATE, GENDER FROM EMPLOYEE WHERE GENDER = 'M'
これが私たちが得る出力です:
上記のように、クエリには女性従業員の詳細のみが入力されました。
サブクエリを使用して結果セットにデータを入力することもできます:
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')
INTERSECTとEXCEPTの制限
- COMPUTE句とCOMPUTEBY句を含む分散パーティションビュー定義でEXCEPTとINTERSECTを使用することはできません。
- EXCEPTおよびINTERSECTは、早送り専用および静的カーソルで使用できます。
- EXCEPTおよびINTERSECTは分散クエリで使用できますが、ローカルサーバーでのみ実行できます。リモートサーバーで実行することはできません。
概要
この記事では、以下について説明しました:
- EXCEPTおよびINTERSECT演算子。
- INTERSECTとINNERJOINの違い。
- 例を使用したINTERSECTおよびEXCEPT演算子の詳細な説明。