FROM 句の副問い合わせ(派生表)の使い方
shain元の表
| name | taishoku_on |
|---|---|
| 山本 | 2024-03-31 |
| 高橋 | 2025-09-30 |
| 鈴木 | NULL |
| … | |
t在籍中だけの表
| name | taishoku_on |
|---|---|
| 鈴木 | NULL |
| 佐藤 | NULL |
| 田中 | NULL |
| … | |
結果部署ごとの人数
| busho_name | ninzu |
|---|---|
| 開発 | 4 |
| 営業 | 3 |
| マーケ | 2 |
| … | |
- 元の表 18 行 → 在籍中だけの表 16 行 → 部署ごとの人数 6 行
- 前の段の結果が次の段の入力になります。表が 1 つ増えたつもりで読んでください
真ん中の t が派生表です。左に写っている退職日入りの 2 人が消えて 16 行になり、それを表として数えて 6 行になりました。
FROM の中に副問い合わせを書くと、その結果を 1 つの表として扱えます。 これを派生表と呼びます。1 つの SELECT では書けない「集計してから絞る」が、段階に分けるだけで書けるようになります。
未確認の製品があります そのまま使える: PostgreSQL / MySQL / MariaDB / SQLite / SQL Server / Oracle Database
未確認: IBM Db2
このページの実行結果と図は、すべて本物のデータベースに同じ SQL を流して得たものです。手で書いた「たぶんこうなる」ではありません。
01副問い合わせの結果を表として使う
結論: FROM (SELECT …) 別名 と書くと、その結果が表になります。
ふつうの副問い合わせは WHERE の中に置いて値として使いますが、派生表は FROM に置いて表として使います。JOIN の相手にもできますし、そこから GROUP BY することもできます。
別名は必ず付けてください。 付けないと、その表の列を指すときに何と書けばよいのか読む人に伝わりません。製品によっては別名が無いとエラーになります。
⚠️ 派生表の中では、外側の列を参照できません。先に作って、あとから使うという順序です。
SELECT b.busho_name, count(*) AS ninzu外側の問い合わせFROM (SELECT * FROM shain★ここから派生表WHERE taishoku_on IS NULL) t★別名 t を必ず付けるJOIN busho b ON b.busho_id = t.busho_id作った表を結合の相手にできるGROUP BY b.busho_name作った表をまとめるORDER BY count(*) DESC, b.busho_name;結果の並べ方
t は元からある表ではありません。この文の中だけで作られ、この文が終わると消えます。
SELECT b.busho_name, count(*) AS ninzu
FROM (SELECT * FROM shain WHERE taishoku_on IS NULL) t
JOIN busho b ON b.busho_id = t.busho_id
GROUP BY b.busho_name
ORDER BY count(*) DESC, b.busho_name;| busho_name | ninzu |
|---|---|
| 開発 | 4 |
| 営業 | 3 |
| マーケ | 2 |
| 基盤 | 2 |
| 管理 | 2 |
| 経営 | 1 |
(6 行)
6 行です。退職者 2 人を除いてから数えているので、開発は 4 人になっています。
02⚠️ よくある間違い:集計してから絞るには段階が要る
結論: WHERE に集約関数は書けません。 集計した結果で絞りたいなら、いったん表にしてから絞ります。
WHERE はまとめる前に評価されるので、その時点では合計も平均もまだありません。書くとエラーになります。
方法は 2 つあります。
HAVING… まとめた直後に絞る。同じ 1 文の中で完結する- 派生表 … いったん集計結果を表にして、その外側で
WHEREを使う
⚠️ どちらでも書けますが、さらに並べ替えや別の表との結合を重ねるなら派生表のほうが素直です。段階が目に見えるぶん、読む人が追いやすくなります。
見分け方は「その条件は、まとめた結果に対するものか」です。WHERE に書けるのは 1 行だけを見て決まる条件、HAVING と派生表の外側に書けるのはまとめた結果を見て決まる条件です。
もう 1 つ、派生表には外側で使える名前が付くという利点があります。内側で sum(salary) AS goukei と名付けておけば、外側では goukei と書くだけで済みます。集約関数をもう一度書く必要がありません。
SELECT busho_id, sum(salary) AS goukei
FROM shain
WHERE sum(salary) > 1500000
GROUP BY busho_id;「aggregate functions are not allowed in WHERE」と出ます。書き方の間違いではなく、評価される順番の問題です。
SELECT busho_id, goukei
FROM (SELECT busho_id, sum(salary) AS goukei
FROM shain
GROUP BY busho_id) t
WHERE goukei > 1500000
ORDER BY goukei DESC;| busho_id | goukei |
|---|---|
| 2 | 2215050 |
| 3 | 2131000 |
| 4 | 1617000 |
(3 行)
3 部署です。内側で部署ごとの合計を出して表にし、その外側の WHERE で 150 万円を超えるものだけに絞っています。
03同じ表を 2 回使うなら WITH を考える
結論: 派生表は書いた場所でしか使えません。 同じものを 2 か所で使いたいなら、WITH で名前を付けるほうが短くなります。
派生表を 2 か所に書くと、同じ SQL が 2 つ並ぶことになります。片方だけ直して食い違う事故が起きやすい形です。
一方で、1 か所でしか使わないなら派生表のほうが素直です。名前を先に定義してから本体を読む形より、その場に書いてあるほうが目で追いやすいこともあります。
⚠️ どちらが速いかは製品と状況によります。読みやすさで選んで、遅ければ両方試すのが現実的です。
SELECT t.busho_id, t.goukei, round(t.goukei / t.ninzu) AS hitori_atari
FROM (SELECT busho_id,
sum(salary) AS goukei,
count(*) AS ninzu
FROM shain
GROUP BY busho_id) t
ORDER BY hitori_atari DESC;| busho_id | goukei | hitori_atari |
|---|---|---|
| 1 | 980000 | 980000 |
| 2 | 2215050 | 553763 |
| 4 | 1617000 | 539000 |
| 5 | 1078000 | 539000 |
| 3 | 2131000 | 532750 |
| 7 | 903000 | 451500 |
| NULL | 832000 | 416000 |
(7 行)
7 行です。合計と人数を同時に作っておけば、その 2 つを使った計算が外側で自由にできます。所属未設定の 2 人も 1 つのまとまりとして出ています。
⚠️ この書き方は SQL Server / IBM Db2 では使えません(round(x)(引数 1 つ))。製品ごとの対応表
自分で打ってみる
このページの例と同じデータが入った本物のデータベースを、この場(あなたのブラウザの中)で起動できます。打った SQL がサーバーへ送られることはありません。
押すと初回だけ約 9MB を読み込みます(2 回目以降はキャッシュされます)。
解いてみる
読んだだけでは書けるようになりません。実行結果で採点します。
関連するトピック
- WITH 句同じ結果に名前を付けて何度も使う書き方です。
- HAVING 句まとめた直後に絞る書き方です。
- GROUP BY 句まとめる操作そのものはこちらです。
- スカラー副問い合わせ値として使う副問い合わせはこちらです。
- ROW_NUMBER / RANK / DENSE_RANK順位で絞るときにも派生表を使います。
根拠(一次情報)
- PostgreSQL 18 マニュアル: FROM 句(副問い合わせと別名)一次情報・確認 2026-08-13
- PostgreSQL 18 マニュアル: 問い合わせの評価順序(WHERE と集約)一次情報・確認 2026-08-13