FROM句のサブクエリ

FROM句のサブクエリ とは

FROM句でサブクエリを使う方法を学習し、複雑なデータ抽出に挑戦します。本レッスンでは、FROM句のサブクエリ の基本から実際の使いどころまでを整理し、現場で迷わず使える形に落とし込みます。

なぜ重要か

「カテゴリ別の平均売上を、さらに高い順に並べたい」「集計した結果を別の集計でフィルタしたい」など、集計を 2 段階で行いたいときFROM 句のサブクエリインラインビュー)が活躍します。FROM 句のサブクエリは「一時的なテーブルを SQL の中に書く」ようなもので、外側のクエリからは普通のテーブルと同じように扱えます。GROUP BY のあとに WHERE で絞り込むという順序問題を、自然な形で解決できる強力なテクニックです。

構文・キーワード解説

基本形は次のようになります。サブクエリには 必ずエイリアス を付けます(MySQL/TiDB は省略不可)。

SQL クエリ

SELECT t.col1, t.col2 FROM ( SELECT col1, col2, COUNT(*) AS cnt FROM tablename GROUP BY col1, col2 ) AS t WHERE t.cnt > 10;

ステップごとの動作

FROM 句のサブクエリは、内側がまるごと評価されて 1 つの一時テーブルになり、その上に外側の SELECT/WHERE/ORDER BY が乗ります。

diagram (will load when visible)

代表例

カテゴリ別の平均価格を、平均が 2000 円以上のものに絞る

SQL クエリ

SELECT category, avg_price FROM ( SELECT category, AVG(price) AS avg_price FROM products GROUP BY category ) AS t WHERE avg_price >= 2000 ORDER BY avg_price DESC;

HAVING でも書けますが、FROM 句のサブクエリにすると「先に集計して、後で絞る」という意図が読み手に伝わりやすくなります。

売上ランキングの上位 3 件にコメントを付ける

SQL クエリ

SELECT rank_no, name, price FROM ( SELECT name, price, RANK() OVER (ORDER BY price DESC) AS rank_no FROM products ) AS r WHERE r.rank_no <= 3;

ウィンドウ関数で計算した順位を WHERE で使うには FROM 句のサブクエリにする必要があります(WHERE では順位列をそのままは参照できないため)。

HAVING との使い分け

観点HAVINGFROM 句のサブクエリ
書きやすさGROUP BY と並べて書ける段階が明示的
列の参照集計関数や GROUP BY 列内側で定義した任意の列名
複雑さ単純な絞り込み向け複数段の集計向け

「集計結果に名前を付けて、次の処理で再利用したい」と感じたら FROM 句のサブクエリ。シンプルな絞り込みだけなら HAVING で十分。

よくある落とし穴

注意 FROM 句のサブクエリにエイリアスを付け忘れると Every derived table must have its own alias というエラーになります。AS t のように必ず別名をつけましょう。

SQL クエリ

-- NG: エイリアスがない SELECT * FROM (SELECT id FROM products); -- OK SELECT * FROM (SELECT id FROM products) AS t;

また、サブクエリの内側で計算した別名(AVG(price) AS avg_price など)は 外側からのみ参照可能 です。同じサブクエリ内では使い回せない点に注意してください。

CTE(次レッスン)との関係

FROM 句のサブクエリは、次レッスンで扱う CTEWITH 句) で書き換えられます。CTE のほうが上から順に読めるため、複数の派生テーブルが必要なときは CTE が有利です。1 つだけならどちらでも構いません。

SQL クエリ

-- FROM 句のサブクエリ SELECT category, avg_price FROM ( SELECT category, AVG(price) AS avg_price FROM products GROUP BY category ) AS t WHERE avg_price >= 1500; -- CTE で書き換え WITH t AS ( SELECT category, AVG(price) AS avg_price FROM products GROUP BY category ) SELECT category, avg_price FROM t WHERE avg_price >= 1500;

FROM 句のサブクエリは「派生テーブル(derived table)」とも呼ばれ、各 DB エンジンの実行計画では一時テーブルとして表示されることが多い。

2 段以上の派生テーブルが必要、または同じ派生テーブルを 2 か所以上で使うなら、最初から CTE で書き始めると読みやすい。

まとめ

  • FROM 句のサブクエリは「一時テーブルを SQL の中に書く」もの
  • 集計結果を再加工したいときに便利(ウィンドウ関数や 2 段集計など)
  • サブクエリには必ずエイリアスを付ける
  • 単純な絞り込みは HAVING、複雑なものは FROM 句のサブクエリ
  • 複数段の派生テーブルが必要なら CTE のほうが読みやすい

次のレッスン

次は SELECT句のサブクエリ です。SELECT句にサブクエリを記述し、より高度なデータ抽出を実践します。

事前確認 — 進む前に次の 3 つができることを確認しましょう。

  1. FROM サブクエリ の要点を自分の言葉で説明できる
  2. このレッスンの最小コード (または操作手順) を見ずに書ける
  3. 練習問題やクイズで間違えた箇所を読み直して理解した

理解度チェック (30 秒)

Q. FROM サブクエリ とは何か、1 文で説明してください。

この章のポイント

A. 本文の「このレッスンで分かること」または冒頭の説明文を見直し、自分の言葉で要約できれば OK。詰まったら本レッスンの最初の H2 セクションを読み返してみましょう。

関連レッスン

テーブル構造

schema.sql

CREATE TABLE products ( id INT PRIMARY KEY, name VARCHAR(40), category VARCHAR(30), price INT ); INSERT INTO products VALUES (1, 'シャープペン', '文具', 200), (2, 'ノート', '文具', 350), (3, '万年筆', '文具', 5000), (4, 'マグカップ', '雑貨', 1200), (5, 'タンブラー', '雑貨', 2500), (6, 'ワイヤレスマウス', '家電', 3200), (7, 'キーボード', '家電', 6800), (8, 'スピーカー', '家電', 4000);

期待される出力

categoryavg_price
家電4666.6667
文具1850.0000
雑貨1850.0000

ヒント

query.sql
query.sql
学習モード
コードの実行結果
データベースを初期化中...