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 が乗ります。
代表例
カテゴリ別の平均価格を、平均が 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 との使い分け
| 観点 | HAVING | FROM 句のサブクエリ |
|---|---|---|
| 書きやすさ | 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 句のサブクエリは、次レッスンで扱う CTE(WITH 句) で書き換えられます。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 つができることを確認しましょう。
- FROM サブクエリ の要点を自分の言葉で説明できる
- このレッスンの最小コード (または操作手順) を見ずに書ける
- 練習問題やクイズで間違えた箇所を読み直して理解した
理解度チェック (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);期待される出力
| category | avg_price |
|---|---|
| 家電 | 4666.6667 |
| 文具 | 1850.0000 |
| 雑貨 | 1850.0000 |