CodeGym /コース /SQL SELF /データ存在チェック with EXISTSNOT EXISTS

データ存在チェック with EXISTSNOT EXISTS

SQL SELF
レベル 13 , レッスン 3
使用可能

SQLの新しいレクチャーへようこそ!今日は一見地味だけどめっちゃ強力なオペレーターEXISTSNOT EXISTS を紹介するよ。まるで痕跡を残さずに「うん、オブジェクトあるよ」または「いや、ここ何もないよ」って即答してくれるスパイみたいなやつ。これらのオペレーターは直接データを返さないけど、論理的に正確なチェックをクエリでできるようにしてくれるんだ。

まずは基本から。EXISTSサブクエリの結果にレコードが存在するかをチェックするオペレーター。サブクエリが1件でもレコードを返せば EXISTSTRUE を返し、なければ FALSE になる。

SELECT 1
WHERE EXISTS (
    SELECT * 
    FROM students 
    WHERE grade > 3.5
);

見ての通り、サブクエリのデータ自体には興味なくて、そういう行が「あるかどうか」だけを見てる。1件でも条件に合うレコードがあれば、クエリは 1 を返すよ。

EXISTS のシンタックス

EXISTS のシンタックスはシンプル:

SELECT カラム
FROM テーブル
WHERE EXISTS (
    SELECT 1
    FROM 別のテーブル
    WHERE 条件
);

解説:

  • EXISTS の中のサブクエリはどんなクエリでもOK。
  • サブクエリの結果が TRUEFALSE かを決める。

例:4より高い成績の学生がいるか?

テーブル students を想像してみて:

id name grade
1 Otto 3.2
2 Anna 4.7
3 Dan 5.0
4 Lina 2.9

例えば、成績が4より高い学生がいるかチェックしたいときはこう書く:

SELECT '高得点の学生がいるよ!'
WHERE EXISTS (
    SELECT 1
    FROM students
    WHERE grade > 4
);

結果:

高得点の学生がいるよ!

なぜ EXISTSIN より速いの?

EXISTS の最大の強みは、最初の一致を見つけた時点でサブクエリの実行を止めること。つまり、データの存在チェックなら EXISTS はめっちゃ効率的なんだ。

例えば、students テーブルに何百万件もレコードがあっても、条件(grade > 4)に合う1件を見つけたら即終了。

NOT EXISTS の使い方

次は NOT EXISTS について話そう。これは EXISTS の逆バージョン。サブクエリが1件もレコードを返さないときに TRUE を返す。

例:成績がない(NULL)の学生を探す

例えば、成績がまだついてない学生がいるとする:

id name grade
1 Otto NULL
2 Anna 4.7
3 Dan 5.0
4 Lina NULL

成績がない学生だけを選びたい。NOT EXISTS を使うと:

SELECT *
FROM students s
WHERE NOT EXISTS (
    SELECT 1
    FROM students 
    WHERE grade IS NOT NULL
    AND id = s.id
);

結果:

id name grade
1 Otto NULL
4 Lina NULL

EXISTSIN の比較

一見 EXISTSIN は同じことをしてるように見える。でも実は違いがある。特に NULL が絡むと IN の挙動が予想外になったり、EXISTS が救世主になったりする。

例で見てみよう。

テーブル courses(受講できるコース):

course_id name
1 数学
2 歴史

そして学生たち:

student_id name
1 Alex Lin
2 Anna Song
3 Maria Chi
4 Dan Seth
5 Shadow Moon

テーブル enrollments(誰がどのコースに登録したか):

student_id course_id
1 1
2 2
3 NULL

誰かが登録しているコース名を選びたい。簡単そうだよね。

IN を使う場合:

SELECT name
FROM courses
WHERE course_id IN (
    SELECT course_id 
    FROM enrollments
);

一見これでOKに見える。でも enrollments の courseid に NULL があると(Maria Chi の場合)、IN は…何も返さないことも!NULL がサブクエリを「未定義」にしてしまい、SQLは「もしかして NULL が探してる courseid かも?」って混乱するんだ。

EXISTS を使う場合:

SELECT name
FROM courses c
WHERE EXISTS (
SELECT 1
FROM enrollments e
WHERE c.course_id = e.course_id
);

でも EXISTS は「course_id が一致する行が1件でもある?」ってだけをチェック。NULL があっても気にしない。具体的な一致だけを探すから。

まとめ:サブクエリに NULL が混じる可能性があるなら、EXISTS を使った方が安心だよ。

リアルな課題例

テーブル students

id name
1 Alex Lin
2 Anna Song
3 Maria Chi
4 Dan Seth
5 Shadow Moon

テーブル enrollments

student_id course_id
1 1
2 2
3 NULL

例1. コースに登録した学生

どこかで登録したことがある学生(Maria Chi みたいな変なケースも含む)を探す:

SELECT name
FROM students s
WHERE EXISTS (
    SELECT 1
    FROM enrollments e
    WHERE s.id = e.student_id
);

結果:

Alex Lin
Anna Song
Maria Chi

enrollments に1件でも出てくれば、その学生は抽出される。course_id が不明でもOK。

例2. コース未登録の学生

今度は、まだどこにも登録してない学生を探す:

SELECT name
FROM students s
WHERE NOT EXISTS (
    SELECT 1
    FROM enrollments e
    WHERE s.id = e.student_id
);

結果:

Dan Seth
Shadow Moon

この2人はまだお気に入りのコースが見つかってないみたい。もしくは登録忘れかも :)

例3. 5人以上登録しているコースの抽出

テーブル courses

course_id name
1 数学
2 歴史
3 生物学
4 哲学

テーブル enrollments

student_id course_id
1 1
2 1
3 1
4 1
5 1
6 1
7 2
8 2
9 2
10 NULL

5人以上登録しているコースを探したい。ここで EXISTS は「このコースに5人以上の学生がいるグループがある?」って聞いてる感じ。

SELECT name
FROM courses c
WHERE EXISTS (
    SELECT 1
    FROM enrollments e
    WHERE c.course_id = e.course_id
    GROUP BY e.course_id
    HAVING COUNT(*) > 5
);

結果:

数学

「数学」(course_id = 1)だけが6人登録されてる。他のコースはまだ人気イマイチ。

EXISTSNOT EXISTS のよくあるミス

  1. サブクエリのシンタックスの誤解。サブクエリが外部テーブルをちゃんと参照してるか必ず確認しよう。
  2. NULL チェックの忘れ。EXISTS を使っても、時には NULL の扱いを明示する必要がある。
  3. サブクエリのフィールドにインデックスがない。これがあるとクエリがめっちゃ遅くなることも。

今日はここまで!これで EXISTSNOT EXISTS を使ったデータ存在チェックや、これらと IN の違いが分かったはず。次のレクチャーでは、SELECT でのサブクエリと集計データの扱いをさらに深掘りするよ。

コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION