EXISTSとNOT EXISTS
SQLで副問合せ、抽出条件のEXISTS句の基本的な使い方を紹介します。
本記事の例で扱う生徒表、部活表の構成は下記となります。
部活
+-----------------+-----------------+-----------+
| 部活コード | 部名 | 種別 |
+-----------------+-----------------+-----------+
| C_001 | 吹奏楽部 | 文化部 |
| C_002 | 美術部 | 文化部 |
| C_003 | 手芸部 | 文化部 |
| S_001 | サッカー部 | 運動部 |
| S_002 | 野球部 | 運動部 |
| S_003 | 水泳部 | 運動部 |
| S_004 | 柔道部 | 運動部 |
+-----------------+-----------------+-----------+
生徒
+--------------+--------------+-----------------------+
| 生徒番号 | 名前 | 所属部活コード |
+--------------+--------------+-----------------------+
| 0001 | 山田太郎 | C_001 |
| 0002 | 鈴木一郎 | S_002 |
| 0003 | 田中二郎 | S_001 |
| 0004 | 山本花子 | S_003 |
| 0005 | 伊藤洋子 | C_002 |
| 0006 | 木村雄一 | NULL |
| 0007 | 中田賢一 | C_001 |
| 0008 | 川井伸二 | S_002 |
+--------------+--------------+-----------------------+
「存在する」行を抽出
WHERE EXISTS : 副問合せの条件に存在する
具体例として上記の生徒表から、生徒が所属する部活の種別が「文化部」である行をEXISTSを使用して全て抽出します。
(文化部所属の生徒を全て抽出)
SELECT student_code 生徒番号, student_name 名前, club_code 所属部活コード FROM student 生徒
WHERE EXISTS (SELECT * FROM club 部活
WHERE 部活.club_code = 生徒.club_code AND club_type = '文化部')
抽出結果
+--------------+--------------+-----------------------+
| 生徒番号 | 名前 | 所属部活コード |
+--------------+--------------+-----------------------+
| 0001 | 山田太郎 | C_001 |
| 0007 | 中田賢一 | C_001 |
| 0005 | 伊藤洋子 | C_002 |
+--------------+--------------+-----------------------+
上記のSQLを分解して解説すると1行目が主問合せとなるSELECTは生徒表の全行が対象となります。
相関サブクエリ
次に、2行目のWHERE句のEXISTS以降の括弧内が副問合せとなりますが、WHERE句でひとつめの条件になっている、
「部活.club_code = 生徒.club_code」は副問合せの中から、主問合せの生徒表との結合を行っています。
こちらは相関サブクエリ(相関副問合せ)とよばれる副問合せの手法で、通常、主問合せよりも先に実行される副問合せと異なり、この場合主問合せの実行1行ごとに副問合せ側のSQLの検索実行を行います。
EXISTS句は副問合せの条件「存在する」が真の場合に主問合せの結果を返しますので、今回の場合、生徒表の中から所属部活コードが副問合わせ内のもうひとつの抽出条件「club_type = ‘文化部’」と合致する行のみを返します。
(EXISTSイメージ)
※ 相関サブクエリ イコール EXISTSというわけではなく、EXISTS、NOT EXISTS以外のSQL文でも相関サブクエリを使うことがあります。
存在しない NOT EXISTS
今度はEXISTS(存在する)とは反対の「存在しない」を条件にする、NOT EXISTSについて解説します。
NOT EXISTSは「NOT」と否定の意味がついているように、主問合せで指定した表から副問合せで抽出した結果に存在しない行を抽出します。
例として、NOT EXISTSを使用して「部活表」から所属する生徒が存在しない部を抽出します。
SELECT club_code 部活コード, club_name 名前, club_type 種別 FROM club
WHERE NOT EXISTS (SELECT * FROM student
WHERE student.club_code = club.club_code)
抽出結果
+-----------------+-----------+-----------+
| 部活コード | 名前 | 種別 |
+-----------------+-----------+-----------+
| C_003 | 手芸部 | 文化部 |
| S_004 | 柔道部 | 運動部 |
+-----------------+-----------+-----------+
EXISTSと同様、相関サブクエリを使って副問合せ内から主問合わせの表との結合条件(部活表の部活コードと生徒の所属部活コード)を指定しています。
今回の主テーブルである部活表の一行ごとに副問合せを実行し、結合できない、つまり生徒の所属部活コードには存在しない部活コードの行データを抽出しています。
NOTをなくして、EXISTSとすれば、部活表から所属する生徒が存在する行のみを抽出します。
(NOT EXISTSイメージ)