0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

サブクエリの書き場所ごとに理解する SQL

Posted at

「サブクエリ=とりあえず (SELECT …) を書くもの」と雑に覚えていました。
しかし、書く場所ごとの役割から考えると理解が深まったのでまとめます。


1. SELECT 句に書くサブクエリ ──「列を増やす」ための道具箱

非相関サブクエリ: 1 回だけ実行して全行に同じ値を貼る

SELECT
  name,
  (SELECT AVG(salary) FROM employees) AS avg_salary
FROM employees;
  • 動き: SELECT AVG(salary) が一度だけ走り、戻り値 1 つを全行に付与
  • 用途: 全体平均・最大値・設定情報など 「全員同じ列値でいい」 ケース

相関サブクエリ: 行ごとに実行して“行に合わせた値”を算出

SELECT
  e1.name,
  (SELECT AVG(e2.salary)
   FROM employees e2
   WHERE e2.department_id = e1.department_id) AS dept_avg_salary
FROM employees e1;
  • 動き: 外側行の department_id ごとに内側が再実行 → 行ごとに異なる値
  • メリット: 部署ごとの平均、顧客ごとの最新注文金額など “行ごとに違う計算” が楽
  • デメリット: 実行回数 = 行数 になるので大規模データだと遅い。JOIN への書き換え検討を。

ここで覚えるポイント
非相関 = “一気に 1 回” → 全行同じ
相関 = “行ごとに再実行” → 行ごとに違う値
SELECT 句の目的は「列を増やす」こと。その列が“全員同じ”か“行ごとに違う”かで相関を選ぶ。


2. FROM 句に書くサブクエリ ──「一時テーブル化」してクエリを分ける

非相関サブクエリだけ(相関は不可)

SELECT sub.department_id, AVG(sub.salary)
FROM (
  SELECT department_id, salary FROM employees
) AS sub
GROUP BY sub.department_id;
  • 動き: SELECT department_id, salary … が 1 度走り、結果セットを “仮テーブル sub” にする
  • 用途: 複雑な計算を切り出して読みやすくする、インラインビュー代わりに使う
  • 相関が不可な理由: FROM 句のサブクエリは “先に独立して完結” してから外側へ渡る設計だから。

覚えるポイント
FROM 句サブクエリ = “作業用ビュー”
外側行を参照できない=相関不可。逆に言えば「外側に依存しないまとまりを切り出す」のに最適。


3. WHERE 句に書くサブクエリ ──「条件を動的に作る」フィルター職人

非相関サブクエリ: 一度だけ実行してしきい値を決める

SELECT name
FROM employees
WHERE salary > (SELECT AVG(salary) FROM employees);
  • 動き: 平均給与を 1 回計算 → その値を境にフィルタ
  • 用途: “全体平均より高い人” “最大売上の製品” など 比較対象が 1 値で済む 場面

相関サブクエリ: 行ごとに条件が変わるフィルター

SELECT e1.name
FROM employees e1
WHERE salary > (
  SELECT AVG(e2.salary)
  FROM employees e2
  WHERE e2.department_id = e1.department_id
);
  • 動き: 外側行の department_id ごとに平均を再計算 → 行ごと評価
  • 用途: “部署平均より高い人” “顧客ごと累計より多い注文” など 行依存の条件
  • 注意: 実行回数 = 行数。パフォーマンス課題がある場合は JOIN + GROUP BY への変換を検討。

覚えるポイント
WHERE 句サブクエリは「**値を返すより“真偽判定に使う”**イメージで書く」とブレにくい。


4. HAVING 句に書くサブクエリ ──「集計結果に“外基準”をぶつける」

非相関サブクエリで全体基準を一発参照

SELECT department_id, AVG(salary)
FROM employees
GROUP BY department_id
HAVING AVG(salary) > (SELECT AVG(salary) FROM employees);
  • 動き: 全体平均を 1 回計算 → 部署ごとの平均と比較
  • 使いどころ: レポート系で 「各グループ vs 全体」 を比べたい場面が定番
  • 相関はほぼ使わない: 相関的に複雑になるなら、CTE/サブクエリをFROM句に切り出す設計を

覚えるポイント
HAVING 句サブクエリは「集計後のロジック」で使う。
外側のGROUP BY結果と比べる“外部基準値”を作るのが主目的。


まとめ ──「どこに書くか」でサブクエリは別物になる

書く場所 典型目的 非相関の動き 相関/動き 代表的な落とし穴
SELECT 列を追加 1回のみ実行 ◯ /行ごと再実行 行数多いと遅い
FROM 一時表化 1回のみ実行 × /不可 読み手がネストに迷う
WHERE 条件値 1回のみ実行 ◯ /行ごと再実行 相関で遅くなる
HAVING 集計比較 1回のみ実行 △ /実用少ない 論理が絡まりやすい
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?