CodeGym /コース /SQL SELF /SELECTの中で SELECTを使う方法

SELECTの中で SELECTを使う方法

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

例えば、君が大学のアナリストとして働いているとしよう(今、大学のデータベースを作ってるって覚えてる?)。学生とその成績を出すだけじゃなくて、グループ内の最高点も一緒に表示して、みんなの成績を簡単に比較できるようにしてほしいって頼まれたんだ。どうやってやる?もちろん、SELECTのサブクエリを使うんだよ!

SELECTのサブクエリを使うと、メインクエリの実行中に値を直接計算できる。これ、めっちゃ便利で、集計計算や複雑なフィルタ、他のデータコレクションも1つのクエリで組み合わせられるんだ。

SELECTのネストされたクエリの基本

SELECTのサブクエリは、文字通りそのまま:1つのSELECTの結果を別のSELECTの中に入れる感じ。これで、結果の各行ごとに追加の値を計算できる。

簡単な例を見てみよう。例えば、studentsテーブルがあって、こんな構造だとする:

student_id name group_id
1 Linda 101
2 Otto 102
3 Anna 101

そしてgradesテーブル:

grade_id student_id grade
1 1 5
2 1 4
3 2 3
4 3 5
5 3 4

例1:グループ内の最高点を追加する

やること:学生の名前と成績、さらにグループ内の最高点も表示して、各学生の成績がグループのベストとどれくらい違うか見えるようにする。

SQLコード:

SELECT
    s.name AS student_name,
    g.grade AS student_grade,
    (
        SELECT MAX(grade) -- このクエリは1つだけ値を返す 
        FROM grades 
        INNER JOIN students ON grades.student_id = students.student_id
        WHERE students.group_id = s.group_id
    ) AS max_group_grade 
FROM 
    students s
INNER JOIN 
    grades g ON s.student_id = g.student_id;

ここで何が起きてるか:

  1. 各学生について、名前と成績を取得(s.name, g.grade)。
  2. SELECT MAX(grade) — これはサブクエリで、その学生のグループ内の最高点を返す。
  3. サブクエリはメインクエリの各行ごとに実行されて、WHERE students.group_id = s.group_idでグループを絞ってる。

例2:グループの平均点

もっとアナリストに優しくしたい?最高点だけじゃなくて、グループの平均点も出力に追加しよう。

SQLコード:

SELECT
    s.name AS student_name,
    g.grade AS student_grade,
    (
        SELECT AVG(grade) 
        FROM grades 
        INNER JOIN students ON grades.student_id = students.student_id
        WHERE students.group_id = s.group_id
    ) AS avg_group_grade
FROM 
    students s
INNER JOIN 
    grades g ON s.student_id = g.student_id;

今度は:

  • MAX()の代わりにAVG()を使って、グループの平均点を計算してる。
  • 「リアルタイム」なデータ分析ができる。

制限とアドバイス

SELECTのサブクエリは強力だけど、使い方には注意が必要:

  1. パフォーマンス。 サブクエリはメインクエリの各行ごとに実行される。テーブルが大きいとSQLクエリの実行が遅くなるかも。例えば、学生が1000人いたら、サブクエリも1000回実行される!
  2. インデックス。 サブクエリのWHERE条件に使うカラムには、ちゃんとインデックスを貼っておくとクエリが速くなるよ。
  3. 読みやすさ。 ネストが深くなりすぎないように注意。サブクエリが複雑になったら、FROMに移したり、一時テーブルを作るのもアリ。

使い方の例

他にも面白いケースをいくつか見てみよう。

例3:各学生の履修コース数

各学生が何コース履修してるかを表示するテーブルを出す。enrollmentsテーブルはstudent_idで学生とつながってる:

student_id course_id
1 201
1 202
2 201
3 203

SQLコード:

SELECT
    s.name AS student_name,
    (
        SELECT COUNT(*) 
        FROM enrollments
        WHERE enrollments.student_id = s.student_id
    ) AS course_count
FROM 
    students s;

ここでは、サブクエリが各学生ごとにenrollmentsテーブルのレコード数を数えてる。

例4:各学生の「優等生」フラグ

学生が優等生かどうかを表示しよう。優等生の基準は、全ての成績が5であることとする。

SQLコード:

SELECT
    s.name AS student_name,
    (
        SELECT CASE 
            WHEN MIN(g.grade) = 5 THEN '優等生'
            ELSE '優等生じゃない'
        END
        FROM grades g
        WHERE g.student_id = s.student_id
    ) AS status
FROM 
    students s;

ここではネストしたCASEを使って、全ての成績が5の学生だけに「優等生」ステータスをつけてる。

SELECTサブクエリの最適化

パフォーマンスが問題になることはすでに言ったよね。改善のためのヒントをいくつか:

  1. インデックスを使おう。 サブクエリでデータを絞るなら、使うカラムにインデックスを貼っておこう。
  2. 結果をキャッシュしよう。 サブクエリをVIEWや一時テーブルに出しておくのもアリ。
  3. ネストは少なめに。 できるだけシンプルな方法を選んで、ネストしすぎないようにしよう。

SELECTのサブクエリは、計算やデータ分析の幅をめっちゃ広げてくれる。リソース食いだけど、ちゃんと最適化すればSQLがもっと表現力豊かで柔軟になるよ。だから、どんどん試して、自分なりのクエリ改善方法を見つけてみて!

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