みなさんこんにちは!
フリーランスプログラマーのsatoです。今回はSQLの「EXISTS」について学んでいきましょう。この「EXISTS」を学ぶことで「サブクエリ」を扱えるようになります。
初心者向けに簡単に説明するなら「SELECT文を入れ子にできる」といえばその用途がなんとなく理解できるのではないかと思います。
- 「EXISTS」とは
- 「EXISTS」の使い方
- 類似機能との使い分け!
- 更新と組み合わせて使ってみよう!
今回は前半で「EXISTS」の基本を学び、後半で応用的な使い方や類似処理との違いについて追求してみます。
「EXISTS」とは
「EXISTS」とは、先ほども言いましたが「サブクエリ」を扱う仕組みです。そしてそのサブクエリは「SELECT文で取得した情報を、他のSELECTやUPDATE処理で使用すること」を指します。
SELECTした結果を使って、さらにSELECT文を回せるわけです。覚えれば強力な武器になりそうですね! 早速使い方を見ていきましょう。
今回使用するテーブル
先ずは使い方を学ぶためのサンプルを見ておきましょう。今回は以下の二つのテーブルを使用し「EXISTS」について学んでいきます。
「user」・・・idと名前が入ったテーブル
「user_sub」・・・idと職種の入ったテーブル
userテーブル:
+------+--------+ | id | name | +------+--------+ | 1 | 山田 | | 2 | 鈴木 | | 3 | 加藤 | | 4 | 田中 | | 5 | 小林 | +------+--------+
user_subテーブル:
+------+--------------------+ | id | job | +------+--------------------+ | 1 | プログラマー | | 2 | プログラマー | | 3 | 営業 | | 4 | 営業 | | 5 | 営業 | +------+--------------------+
「EXISTS」の使い方
では使い方について見てきます。
基本的な使い方
まず基本的な使い方です。一番シンプルな書き方は以下の通りです。
SELECT [表示要素名] FROM [テーブル名] WHERE EXISTS ( [入れ子にするSELECT文] );
見ていただければわかると思いますが、基本的にEXISTSはWHERE句の中で使用することになります。そこだけ記憶に止めつつ、ここからは実際に使って見たほうが理解しやすいのでサンプルを用いた実例を見てみましょう。
簡単な実例
例えば、職種が「プログラマー」の人の情報を取得するのならば、以下のように書きます。
実行処理:
SELECT * FROM user WHERE EXISTS ( SELECT * FROM user_sub WHERE user.id = user_sub.id AND user_sub.job = "プログラマー" );
実行結果:
+------+--------+ | id | name | +------+--------+ | 1 | 山田 | | 2 | 鈴木 | +------+--------+
ちゃんと、プログラマーの人の情報だけ取得できていますね! といってもまだ説明が足りていないので、わけがわからないと思います。引き続きこの処理の詳細を見ていきます。
SELECT同士のひも付き
先ほど実行した以下の処理の詳細を見ていきます。
SELECT * FROM user WHERE EXISTS ( SELECT * FROM user_sub WHERE user.id = user_sub.id AND user_sub.job = "プログラマー" );
この内容を理解する上で、二つ覚えなければならないことがあります。
「user.id」という表記
まず見慣れない「user.id」という表記ですが、これは「テーブル名.要素名」とすることで、どのテーブルの、どの要素なのか? を指定しているわけです。
今回は「userテーブル」と「user_subテーブル」が存在しています。そのためどちらのidなのかを指定する必要があるわけですね!
テーブル同士のひも付き
それを踏まえた上で、この処理の「特に重要な箇所」は以下の入れ子側のWHERE句の前半です。
WHERE user.id = user_sub.id AND user_sub.job = "プログラマー"
前半の「user.id = user_sub.id」部分で、テーブル同士のひも付けを指定しているわけです。これによって、userテーブル側と、user_subテーブル側で連携が取れているわけですね。
仮にこの一文がなく「WHERE user_sub.job = “プログラマー”」だけだったとしたら、以下のように全部が表示されてしまいます。
実行処理:
SELECT * FROM user WHERE EXISTS ( SELECT * FROM user_sub WHERE user_sub.job = "プログラマー" );
実行結果:
+------+--------+ | id | name | +------+--------+ | 1 | 山田 | | 2 | 鈴木 | | 3 | 加藤 | | 4 | 田中 | | 5 | 小林 | +------+--------+
テーブル同士のひも付きがないため、全部表示されてしまうわけです。
[補足]入れ子のSELECT文の表示要素
また、user_sub側で表示する要素を「 * 」としていますが、これは何を指定しても違いはありません。情報さえ取得できれば「情報が取得できた(TRUE)」と判断されるためです。そのため基本的に*(全部表示)を指定すれば問題ありません。
否定形は「NOT EXISTS」
否定形も存在します。その場合はシンプルに、頭に「NOT」をつけて「NOT EXISTS」と書きましょう。
実行処理:
SELECT * FROM user WHERE NOT EXISTS ( SELECT * FROM user_sub WHERE user.id = user_sub.id AND user_sub.job = "プログラマー" );
実行結果:
+------+--------+ | id | name | +------+--------+ | 3 | 加藤 | | 4 | 田中 | | 5 | 小林 | +------+--------+
プログラマーじゃない人たちが、一覧表示されましたね!
類似機能との使い分け!
ここまででEXISTSの使い方を一通り見てきました。しかし実はSQLには「サブクエリを操作する命令」がEXISTS以外にもいくつか存在します。それらとの違いを簡単に見てみましょう。
「IN」との違いは?
IN句は、以下のように使用することでサブクエリを扱うことができます。
SELECT * FROM [テーブルA] WHERE [要素名] IN ( SELECT [要素名] FROM [テーブルB] );
EXISTSとの一番の違いは[要素名] を指定することです。「この要素が存在する場合は表示する」という指定の仕方をすることになります。
またそういった影響でインデックスの使われ方が大きく変わってくるため、処理を最適化するなら状況によってどちらを使用するか選ぶべきでしょう。とは言っても、初心者の方は、まだそこまで気にする必要はありません。まずは正しく動く製品を作ることが重要ですね!
またIN句の詳細は以下にまとめてあります。
「JOIN」との違いは?
JOINは非常に汎用性の高い処理です。基本的にEXISTSでできることは、JOINで実現できます。
初心者の方はまずは「より細かいことをしたい場合はJOINを選ぶ」「シンプルに書きたい場合はEXISTSを選ぶ」ような認識でいて頂ければよいかと思います。また「JOIN」の詳細は以下にありますので、ぜひ読んでみてください。
UPDATEと組み合わせて使ってみよう!
EXISTSは、UPDATEで使用することも可能です。例えばプログラマーだけidに1000を足して足す場合は、以下の通りです。
実行処理:
UPDATE user SET id = id + 1000 WHERE EXISTS ( SELECT * FROM user_sub WHERE user.id = user_sub.id AND user_sub.job = "プログラマー" );
実行後のテーブルの中身:
+------+--------+ | id | name | +------+--------+ | 1001 | 山田 | | 1002 | 鈴木 | | 3 | 加藤 | | 4 | 田中 | | 5 | 小林 | +------+--------+
簡単ですね!
まとめ
今回はEXISTSという命令について見てきました。シンプルにサブクエリを扱えるという非常に優秀な命令ですね!
SELECT文だけでなくUPDATE文にも使用できますし、応用の幅が広い命令です。ぜひ今日覚えたことを、実践で使って自分のものにしていきましょう。