はじめに
「集計したい」時、GROUP BYを使うべきかウィンドウ関数を使うべきか迷う方は多いはずです。本記事では両者の本質的な違いと、実務での判断基準を整理します。
ウィンドウ関数についての記事
この後の流れ
- 最大の違い:行数が変わるか変わらないか
- 同じ元データでの出力比較
- 使い分けの判断基準
- 両方を組み合わせるケース
- まとめ
1. 最大の違い:行数が変わるか変わらないか
| 観点 | GROUP BY | ウィンドウ関数(OVER) |
|---|---|---|
| 出力行数 | グループ数に集約される(減る) | 元の行数を維持する |
| 明細データ | 失われる(集計値のみ残る) | 明細を保持しつつ集計値を付与できる |
| SELECT句の制約 | 集計関数か、GROUP BYの列のみ | 通常の列も集計値も同時に書ける |
| 主な用途 | サマリーレポート、集計表 | ランキング、累計、前後比較、明細+集計の同時出力 |
2. 同じ元データでの出力比較
元データ:社員ごとの給与(部署A, B)
GROUP BYの場合(部署ごとに集約)
SELECT department, AVG(salary) AS avg_salary
FROM employees
GROUP BY department;
| department | avg_salary |
|---|---|
| A | 450 |
| B | 500 |
→ 社員個人の情報は失われ、2行に集約される。
ウィンドウ関数の場合(明細を維持)
SELECT
employee_name,
department,
salary,
AVG(salary) OVER (PARTITION BY department) AS dept_avg_salary
FROM employees;
| employee_name | department | salary | dept_avg_salary |
|---|---|---|---|
| 田中 | A | 400 | 450 |
| 佐藤 | A | 500 | 450 |
| 鈴木 | B | 500 | 500 |
| 高橋 | B | 500 | 500 |
→ 社員ごとの行を維持したまま、部署平均という集計値を付与できる。
3. 使い分けの判断基準
Q1. 明細行(個々のレコード)を残す必要があるか?
├─ NO → GROUP BY(集計表・サマリーレポート)
└─ YES → Q2へ
Q2. 順位付け・累計・前後比較が必要か?
├─ YES → ウィンドウ関数
└─ NO → スカラサブクエリでも代替可(ただし性能面でウィンドウ関数が有利なことが多い)
具体的なシーン別の対応表:
| やりたいこと | 適した手法 |
|---|---|
| 部署別の合計・平均だけ欲しい | GROUP BY |
| 社員一覧に部署平均も並べて出したい | ウィンドウ関数 |
| 各部署のTOP3社員を抽出したい | ウィンドウ関数(RANK等) |
| 月別売上合計の一覧 | GROUP BY |
| 日次売上と累計売上を同時に見たい | ウィンドウ関数(フレーム指定) |
| カテゴリ別の商品数を数えたい | GROUP BY |
4. 両方を組み合わせるケース
GROUP BYで集約した結果に対して、さらにウィンドウ関数でランキングを付けることも可能です。
SELECT
department,
total_salary,
RANK() OVER (ORDER BY total_salary DESC) AS dept_rank
FROM (
SELECT department, SUM(salary) AS total_salary
FROM employees
GROUP BY department
) AS dept_summary;
「部署別の給与合計を出し、その合計額で部署にランキングを付ける」といった二段階の要件は、GROUP BYとウィンドウ関数の併用で実現します。
5. まとめ
| 判断軸 | GROUP BY | ウィンドウ関数 |
|---|---|---|
| 行が減ってよいか | 減ってよい | 減ってはいけない |
| 目的 | サマリー生成 | ランキング・累計・比較分析 |
| SQLの実行順序上の位置 | WHERE後、HAVING前に評価 | SELECT句評価時(WHERE/GROUP BYより後) |
豆知識: SQLの論理的な実行順序は
FROM → WHERE → GROUP BY → HAVING → SELECT(ウィンドウ関数はここ) → ORDER BY です。
ウィンドウ関数の結果に対してさらにWHEREで絞ることはできず、絞りたい場合はCTEやサブクエリで一段階分ける必要があります。
さいごに
「行を減らしたいか、維持したいか」という一点で考えると、GROUP BYとウィンドウ関数の選択に迷わなくなります。次回はUNIONについて解説します。