ユーザーテーブルと、そのユーザーが好きなプログラミング言語というテーブルがあるとします。
ユーザーテーブル(UserTable)
id | name |
---|---|
1 | 山田 |
2 | 村上 |
3 | 中村 |
好きなプログラミング言語テーブル(FavLangTable)
id | user_id | lang |
---|---|---|
1 | 1 | Python |
2 | 1 | PHP |
3 | 2 | TypeScript |
4 | 2 | C# |
5 | 2 | Java |
6 | 3 | TypeScript |
INとEXISTSの使い分け
結合先のレコードを全て欲しい場合は、EXISTS。そうでない場合は、INを使う。
TypeScriptが好きなユーザーを引いてくるSQLをINで書くとこうなる。
SELECT ut.name, f.lang FROM user_table AS ut JOIN fav_lang_table AS f ON f.user_id = ut.id WHERE f.lang IN("TypeScript")
結合先をINで絞っているので、そのレコードのみが返却されるため、こうなる。
name | lang |
---|---|
村上 | TypeScript |
中村 | TypeScript |
TypeScriptが好きなユーザーを抽出するならこれでいい。だが、TypeScriptが好きなユーザーの「他の全てのプログラミング言語」を同時に取得したい場合、うまくいかない。結合先をINで絞り込んでしまうと、結合先のレコードしか取得しないので。
こーゆー時は、EXISTSの出番。EXISTSはそのレコードの存在有無だけを見てくれるので、JOINした結合先のレコードを丸々取ってくる。
SELECT ut.username, f.lang FROM user_table AS ut JOIN fav_lang_table AS f ON f.user_id = ut.id WHERE EXISTS ( SELECT * FROM fav_lang_table AS f1 WHERE f1.lang IN("TypeScript") AND f1.user_id = ut.id )
こうなる。
name | lang |
---|---|
村上 | TypeScript |
村上 | C# |
村上 | Java |
中村 | TypeScript |
EXISTSはINに比べると可読性が下がる(ぱっと見て内容がわかりにくい)が、使いこなせると楽しいよ。