T-SQL の INTERSECT 演算子

T-SQL の INTERSECT 演算子

前回 「 UNION と UNION ALL で結合 」 では、UNION 演算子を使って、2 つの結果セットをひとつに結合してみました。

今回は INTERSECT 演算子を使って、2 つの結果セットのどちらにも存在する値のみを取得してみましょう。


INTERSECT 演算子

INTERSECT は、指定した左右の結果セットの両方に存在する値のみを返してくれるオペレータで、構文は次の通りです。

[ クエリー 1 ] INTERSECT [ クエリー 2 ]

UNION と同様に、それぞれのクエリーは、カラムの数、順番が一致 していなければなりません。

また、データ型も一致しているか、暗黙に同じ型に変換可能 なものでなければなりません。


結果セットのカラム名は一番左で指定したクエリーのカラム名が使われます。

結果セットの並び順を指定したい時には ORDER BY 句を 最後のクエリー に指定します。 その際も、一番左で指定したカラム名を使います。


それでは、INTERSECT を使ってみましょう。

次のような #Users テーブルと #Students テーブルがあるとします。

CREATE TABLE #Users (
	UserID		INT,
	FirstName	NVARCHAR(50),
	LastName	NVARCHAR(50)
);

INSERT INTO #Users 
	(UserID, FirstName, LastName)
VALUES
	(1, 'Yukari', 'Naito'),
	(2, 'Hiroki', 'Takagi'),
	(3, 'Takahiro', 'Sato'),
	(4, 'Nao', 'Tabata'),
	(5, 'Hanako', 'Tanaka');

-----------------------------------------

CREATE TABLE #Students (
	StudentID	INT,
	FirstName	NVARCHAR(50),
	LastName	NVARCHAR(50)
);

INSERT INTO #Students 
	(StudentID, FirstName, LastName)
VALUES
	(1, 'Taro', 'Yamada'),
	(2, 'Hanako', 'Tanaka'),
	(3, 'Yuko', 'Suzuki'),
	(4, 'Takao', 'Sato'),
	(5, 'Hiroki', 'Takagi'),
	(6, 'Yuka', 'Kimura');

T-SQL の INTERSECT 演算子 1


FirstName と LastName カラムを取得する SELECT 文を INTERSECT を使って結合し、LastName 順にならべると次のようになります。

SELECT		FirstName,
		LastName
FROM		#Users
INTERSECT
SELECT		FirstName,
		LastName
FROM		#Students
ORDER BY	LastName;

[ 実行結果 ]
T-SQL の INTERSECT 演算子 2

#Users テーブルと #Students テーブルのどちらのテーブルにも FirstName と LastName が存在する二人のレコードが結果セットとして取得できました。

INTERSECT 演算子と INNER JOIN の違い

これだけ見ると #Users テーブルと #Students テーブルを以下のように INNER JOIN したのと同じように見えますが、大きく違う点があります。

SELECT	U.FirstName,
	U.LastName
FROM	#Users AS U
	   INNER JOIN #Students AS S
	      ON U.FirstName = S.FirstName
	         AND U.LastName = S.LastName
ORDER BY LastName;

[ 実行結果 ]
T-SQL の INTERSECT 演算子 3


まず、INTERSECT は DISTINCT の値を返します。

例えば、先程の #Users テーブルに同姓同名の人を一人追加して、上の INTERSECT のクエリーを実行しても、得られる結果セットは同じになります。

一方 INNER JOIN のほうは、DISTINCT を指定しない限り、同姓同名でも別々の行として取得されます。

INSERT INTO #Users 
	(UserID, FirstName, LastName)
VALUES
	(6, 'Hiroki', 'Takagi');

-----------------

SELECT	FirstName,
	LastName
FROM	#Users
INTERSECT
SELECT	FirstName,
	LastName
FROM	#Students
ORDER BY LastName;

-----------------

SELECT	U.FirstName,
	U.LastName
FROM	#Users AS U
	   INNER JOIN #Students AS S
	      ON U.FirstName = S.FirstName
	         AND U.LastName = S.LastName
ORDER BY LastName;

[ 実行結果 ]
T-SQL の INTERSECT 演算子 4


もうひとつ、大きな違いは、NULL の扱いです。

INTERSECT は NULL 同士をイコール とみなし、左右のクエリーの結果が両方 NULL の場合はレコードを返します。

一方 INNER JOIN の結合の条件では NULL = NULL は false なので、両方 NULL でマッチしていても NULL のレコードは返ってきません。

#Users テーブルと #Students テーブルの両方に NULL のレコードを挿入して、同じクエリーを実行してみましょう。

INSERT INTO #Users 
	(UserID, FirstName, LastName)
VALUES
	(7, NULL, NULL);

INSERT INTO #Students 
	(StudentID, FirstName, LastName)
VALUES
	(7, NULL, NULL);

-----------------

SELECT	FirstName,
	LastName
FROM	#Users
INTERSECT
SELECT	FirstName,
	LastName
FROM	#Students
ORDER BY LastName;

-----------------

SELECT	U.FirstName,
	U.LastName
FROM	#Users AS U
	   INNER JOIN #Students AS S
	      ON U.FirstName = S.FirstName
	         AND U.LastName = S.LastName
ORDER BY LastName;

[ 実行結果 ]
T-SQL の INTERSECT 演算子 5

INTERSECT のほうは FirstName と LastName が NULL のレコードも結果セットに含まれていますね!

© 2010-2024 SQL Server 入門