LESSON 30分

FROM句とEXISTSを活用しよう

ストーリー

「サブクエリはWHERE句だけじゃない。FROM句にも使えるんだ」

「FROM句に?テーブルの代わりにサブクエリを書くってことですか?」

「その通り。サブクエリの結果を一時的なテーブルとして扱える。あと、EXISTSっていう強力な武器もある」

「EXISTS...なんだか強そうですね」

「実務では IN より EXISTS のほうが効率的なケースも多い。両方覚えておこう」


FROM句でのサブクエリ(派生テーブル)

FROM句にサブクエリを書くと、その結果を**一時的なテーブル(派生テーブル)**として使えます。

基本構文

sql
SELECT カラム名
FROM (
    SELECT ... FROM ... WHERE ...
) AS 派生テーブル名;

注意: FROM句のサブクエリには必ずエイリアス(AS 名前)をつける必要があります。


例1: 部署ごとの集計結果に対して条件を適用

sql
-- 平均給与が40万以上の部署だけを取得
SELECT *
FROM (
    SELECT
        d.name AS 部署名,
        COUNT(e.id) AS 社員数,
        ROUND(AVG(e.salary)) AS 平均給与
    FROM departments d
    INNER JOIN employees e ON d.id = e.department_id
    GROUP BY d.name
) AS dept_stats
WHERE 平均給与 >= 400000;

HAVINGでも同じことができますが、集計結果に対してさらに複雑な処理(JOIN等)を行いたい場合は派生テーブルが便利です。

例2: 部署の集計結果と部署テーブルをJOIN

sql
SELECT
    d.name AS 部署名,
    d.budget AS 年間予算,
    stats.社員数,
    stats.平均給与,
    d.budget / stats.社員数 AS 一人あたり予算
FROM departments d
INNER JOIN (
    SELECT
        department_id,
        COUNT(*) AS 社員数,
        ROUND(AVG(salary)) AS 平均給与
    FROM employees
    GROUP BY department_id
) AS stats ON d.id = stats.department_id;

結果:

部署名年間予算社員数平均給与一人あたり予算
開発部500000034433331666666
営業部300000033866671000000
人事部200000024000001000000
マーケティング部400000024150002000000

EXISTS / NOT EXISTS

EXISTSは、サブクエリが1行以上の結果を返すかどうかを判定します。

基本構文

sql
SELECT カラム名
FROM テーブルA
WHERE EXISTS (
    SELECT 1 FROM テーブルB WHERE テーブルB.カラム = テーブルA.カラム
);

SELECT 1 は慣例的な書き方です。EXISTSは「結果が存在するか」だけを判定するため、SELECTで何を返すかは関係ありません。


例3: プロジェクトに参加している社員(EXISTS版)

sql
-- IN版
SELECT name FROM employees
WHERE id IN (SELECT employee_id FROM project_members);

-- EXISTS版(同じ結果)
SELECT e.name
FROM employees e
WHERE EXISTS (
    SELECT 1 FROM project_members pm
    WHERE pm.employee_id = e.id
);

例4: プロジェクトに参加していない社員(NOT EXISTS版)

sql
SELECT e.name, e.position
FROM employees e
WHERE NOT EXISTS (
    SELECT 1 FROM project_members pm
    WHERE pm.employee_id = e.id
);

結果:

nameposition
山田花子マネージャー
中村大輔人事担当

IN vs EXISTS の違い

動作の違い

特徴INEXISTS
動作サブクエリを全件実行 → リストと比較1行見つかった時点で終了
NULLの扱いNOT IN はNULLで問題ありNOT EXISTSはNULL安全
相関非相関サブクエリ向き相関サブクエリ向き

使い分けの目安

サブクエリの結果が少量 → IN でOK
サブクエリの結果が大量 → EXISTS のほうが効率的
NULLの可能性がある   → EXISTS(NOT EXISTS)が安全

相関サブクエリ(Correlated Subquery)

相関サブクエリは、外側のクエリの値を内側のサブクエリが参照するパターンです。

例5: 各部署で最高給与の社員を探す

sql
SELECT e.name, e.salary, d.name AS 部署名
FROM employees e
INNER JOIN departments d ON e.department_id = d.id
WHERE e.salary = (
    SELECT MAX(e2.salary)
    FROM employees e2
    WHERE e2.department_id = e.department_id  -- 外側の e を参照
);

結果:

namesalary部署名
田中太郎500000開発部
高橋美咲480000営業部
山田花子460000人事部
小林さくら470000マーケティング部

サブクエリ内の e2.department_id = e.department_id が、外側の行ごとに異なる値で評価されます。そのため、各部署での最高給与と比較されます。

例6: 平均給与以上の社員が2人以上いる部署

sql
SELECT d.name AS 部署名
FROM departments d
WHERE (
    SELECT COUNT(*)
    FROM employees e
    WHERE e.department_id = d.id
      AND e.salary >= (SELECT AVG(salary) FROM employees)
) >= 2;

まとめ

ポイント内容
FROM句サブクエリサブクエリの結果を一時テーブルとして使用(エイリアス必須)
EXISTSサブクエリが結果を返すか判定(1行見つかれば終了)
NOT EXISTSサブクエリが結果を返さないか判定(NULL安全)
相関サブクエリ外側のクエリの値を内側で参照する
IN vs EXISTS少量データはIN、大量データやNULLありはEXISTS

チェックリスト

  • FROM句で派生テーブルを作れる
  • EXISTS / NOT EXISTS の構文を書ける
  • IN と EXISTS の違いを説明できる
  • 相関サブクエリの動作を理解した

次のステップへ

サブクエリの主要パターンを学びました。 次のセクションでは、行ごとに集計ができる「ウィンドウ関数」を学びます。 GROUP BYとは異なる、より柔軟な集計手法です。


推定読了時間: 30分