[SQLのはじめ方] Part14: 副問い合わせ(サブクエリ)の基本

SQL

SQLクエリの中に別のSQLクエリを埋め込むテクニックを学ぼう!💡

これまでのステップでは、1つのSQLクエリでデータを取得したり、テーブルを結合したりする方法を学びましたね。今回は、さらに複雑なデータ操作を可能にする「副問い合わせ(サブクエリ)」について解説します。サブクエリをマスターすれば、より柔軟で強力なデータ分析ができるようになりますよ!💪

1. 副問い合わせ(サブクエリ)とは?

副問い合わせ(サブクエリ)とは、SQL文の中に含まれる別のSELECT文のことです。外側のクエリ(主問い合わせ、親クエリとも呼ばれます)を実行する前に、内側のクエリ(サブクエリ)が実行され、その結果が外側のクエリで利用されます。

サブクエリは、主に以下の場所で使用されます。

  • WHERE句:条件指定にサブクエリの結果を利用する。
  • SELECT句:サブクエリの結果を列の値として表示する(スカラーサブクエリ)。
  • FROM句:サブクエリの結果を一時的なテーブル(インラインビュー)として利用する。

言葉だけだと少し難しいかもしれませんね🤔。具体的な例を見ていきましょう!

例として、以下の2つのテーブルを使用します。

employees テーブル (従業員情報)

id name department_id salary
1 山田太郎 1 300000
2 鈴木花子 2 350000
3 佐藤健太 1 400000
4 田中美咲 3 280000
5 高橋一郎 2 420000

departments テーブル (部署情報)

id name
1 営業部
2 開発部
3 人事部

2. 基本的な使い方

2.1 WHERE句での利用

WHERE句でサブクエリを使うと、ある条件を満たすデータの情報を元に、別のデータを検索できます。

例:開発部(department_id = 2)に所属する従業員の名前を取得する

まず、部署名から部署IDを取得するサブクエリを作成し、その結果を使って従業員を検索します。

SELECT name
FROM employees
WHERE department_id = (SELECT id FROM departments WHERE name = '開発部');

実行の流れ:

  1. サブクエリ (SELECT id FROM departments WHERE name = '開発部') が実行され、結果として 2 が返されます。
  2. 主問い合わせが SELECT name FROM employees WHERE department_id = 2; として実行されます。
  3. 結果として「鈴木花子」と「高橋一郎」が返されます。

このように、サブクエリを使うことで、部署IDを直接知らなくても部署名から従業員を検索できます。✅

演算子 IN を使った例:営業部または開発部に所属する従業員の名前を取得する

SELECT name
FROM employees
WHERE department_id IN (SELECT id FROM departments WHERE name IN ('営業部', '開発部'));

実行の流れ:

  1. サブクエリ (SELECT id FROM departments WHERE name IN ('営業部', '開発部')) が実行され、結果として 12 が返されます。
  2. 主問い合わせが SELECT name FROM employees WHERE department_id IN (1, 2); として実行されます。
  3. 結果として「山田太郎」「鈴木花子」「佐藤健太」「高橋一郎」が返されます。

2.2 SELECT句での利用(スカラーサブクエリ)

SELECT句でサブクエリを使う場合、そのサブクエリは必ず単一の行、単一の列(つまり、1つの値)を返す必要があります。これを「スカラーサブクエリ」と呼びます。

例:各従業員の名前と、その従業員が所属する部署名を取得する

SELECT
  e.name,
  (SELECT d.name FROM departments d WHERE d.id = e.department_id) AS department_name
FROM
  employees e;

実行の流れ:

  1. employees テーブルの各行に対して、サブクエリが実行されます。
  2. 例えば、`山田太郎` (department_id=1) の行では、(SELECT d.name FROM departments d WHERE d.id = 1) が実行され、「営業部」が返されます。
  3. この結果が `department_name` という列名で表示されます。

この例は JOIN を使っても実現できますが、スカラーサブクエリは特定のケースで簡潔に書ける場合があります。

⚠️ スカラーサブクエリが複数の行や列を返すとエラーになります。必ず1つの値だけを返すように注意しましょう。

2.3 FROM句での利用(インラインビュー)

FROM句でサブクエリを使うと、サブクエリの結果を一時的な仮想テーブルとして扱うことができます。これを「インラインビュー」と呼びます。インラインビューには、通常 `AS` を使って別名を付けます。

例:各部署の平均給与を計算し、その平均給与が350000以上の部署名を取得する

SELECT
  dept_avg.department_name
FROM
  (
    SELECT
      d.name AS department_name,
      AVG(e.salary) AS avg_salary
    FROM employees e
    JOIN departments d ON e.department_id = d.id
    GROUP BY d.name
  ) AS dept_avg -- サブクエリの結果を dept_avg という名前のインラインビューとする
WHERE
  dept_avg.avg_salary >= 350000;

実行の流れ:

  1. FROM句内のサブクエリが実行されます。このサブクエリは部署ごとに平均給与を計算し、`department_name` と `avg_salary` の2列を持つ結果セットを返します。
  2. この結果セットが `dept_avg` という名前の一時テーブルとして扱われます。
  3. 主問い合わせが `dept_avg` テーブルに対して実行され、`avg_salary` が 350000 以上の行の `department_name` を選択します。
  4. 結果として「開発部」が返されます(営業部の平均: (300000+400000)/2=350000, 開発部の平均: (350000+420000)/2=385000)。

インラインビューを使うことで、複雑な集計処理などを段階的に行い、クエリ全体を整理しやすくなります。✨

3. よく使われる演算子

サブクエリと組み合わせてよく使われる演算子をいくつか紹介します。

  • IN / NOT IN: サブクエリが返す複数の値のいずれかに一致する(または一致しない)レコードを検索します。 (WHERE句の例で既に使用しましたね!)
    -- 営業部(1)または開発部(2)に所属する従業員
    SELECT name FROM employees WHERE department_id IN (SELECT id FROM departments WHERE name IN ('営業部', '開発部'));
  • EXISTS / NOT EXISTS: サブクエリが1行でも結果を返すかどうかを判定します。結果の値自体は比較せず、行が存在するかどうかだけを見ます。
    -- 従業員が1人でも所属している部署の名前を取得する
    SELECT name
    FROM departments d
    WHERE EXISTS (SELECT 1 FROM employees e WHERE e.department_id = d.id);

    (SELECT 1 の部分は、実際に値を取得する必要がないため、定数や * を使うのが一般的です)

  • 比較演算子 (=, >, <, >=, <=, <> or !=): サブクエリが単一の値(スカラー値)を返す場合に使用できます。
    -- 全従業員の平均給与よりも高い給与をもらっている従業員
    SELECT name, salary
    FROM employees
    WHERE salary > (SELECT AVG(salary) FROM employees);
  • ANY / SOME, ALL: 比較演算子と組み合わせて使用し、サブクエリが返す複数の値と比較します。
    • = ANY(サブクエリ): IN と同じ意味です。
    • > ANY(サブクエリ): サブクエリ結果のどれか一つより大きければ真。
    • > ALL(サブクエリ): サブクエリ結果のすべてより大きければ真。
    -- いずれかの部署の平均給与よりも高い給与をもらっている従業員
    SELECT name, salary
    FROM employees
    WHERE salary > ANY (SELECT AVG(salary) FROM employees GROUP BY department_id);

4. 注意点 ⚠️

サブクエリは非常に便利ですが、いくつか注意点があります。

  • パフォーマンス: サブクエリ、特に相関サブクエリ(主問い合わせの各行に対してサブクエリが実行されるタイプ)は、使い方によってはパフォーマンスが低下する可能性があります。大きなテーブルに対して実行する場合は、JOIN など他の方法で書き換えられないか検討しましょう。実行計画を確認する癖をつけると良いでしょう。
  • 可読性: サブクエリを多用しすぎると、クエリがネストして読みにくくなることがあります。インラインビューや後述するCTE(共通テーブル式)などを活用して、クエリの構造を分かりやすく保つことが重要です。
  • エラー: スカラーサブクエリが複数の値を返したり、比較演算子で使うサブクエリが複数の値を返したりするとエラーになります。サブクエリが返す行数と列数を意識してクエリを作成しましょう。

5. まとめ

今回は、SQLの強力な機能である「副問い合わせ(サブクエリ)」の基本的な使い方について学びました。

  • サブクエリはSQL文の中に書く別のSELECT文です。
  • WHERE句、SELECT句、FROM句などで利用できます。
  • IN, EXISTS, 比較演算子などと組み合わせて複雑な条件を指定できます。
  • パフォーマンスや可読性には注意が必要です。

サブクエリを使いこなせるようになると、データ抽出や分析の幅が格段に広がります。色々なパターンで試してみて、ぜひマスターしてくださいね!😊

次は、複数のSELECT結果を結合する「UNIONとUNION ALLの違い」について学びます。お楽しみに!

学習進捗:Step 4 複数テーブルの操作 – 副問い合わせ(サブクエリ)の基本 (完了) ✅
次のステップ:UNIONとUNION ALLの違い

コメント

タイトルとURLをコピーしました