SQLを使用してデータを集計していると、
「グループごとに最大値を持つ行そのものを取得したい」
という場面は非常に多くあります。
例えば、以下のような要件です。
- 部署ごとに最も給与が高い社員の行を取得したい
- 商品ごとに最新の更新日時のレコードを取得したい
- ユーザーごとに最大スコアを記録した行を抽出したい
単純な MAX() 集計関数だけでは行全体は取得できないため、少し工夫が必要になります。
本記事では、代表的かつ安全な書き方を順に解説します。

目次
前提となるサンプルデータ
以下のようなテーブルを例に説明します。
sales テーブル
| dept_id | employee | amount |
|---|---|---|
| 10 | A | 100 |
| 10 | B | 200 |
| 20 | C | 150 |
| 20 | D | 300 |
このテーブルから、
部署(dept_id)ごとに売上額(amount)が最大の行を取得します。
方法① サブクエリ+JOIN(最も基本的な書き方)
まず、グループごとの最大値をサブクエリで取得し、それを元テーブルと結合する方法です。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
SELECT s.dept_id, s.employee, s.amount FROM sales s JOIN ( SELECT dept_id, MAX(amount) AS max_amount FROM sales GROUP BY dept_id ) m ON s.dept_id = m.dept_id AND s.amount = m.max_amount; |
ポイント
GROUP BYで 部署ごとの最大値 を取得- 最大値と一致する行を
JOINで結合 - 複数行が最大値の場合はすべて取得される
実務で最もよく使われる、可読性と安全性の高い書き方です。
方法② 相関サブクエリを使う方法
次に、行ごとに最大値と比較する方法です。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
SELECT dept_id, employee, amount FROM sales s WHERE amount = ( SELECT MAX(amount) FROM sales WHERE dept_id = s.dept_id ); |
ポイント
- 外側の行と内側のサブクエリを関連付けています
- SQLとしてはシンプルですが、
件数が多い場合は性能に注意が必要です
小規模データや簡易な分析用途で使われることが多い方法です。
方法③ ウィンドウ関数(分析関数)を使う方法
ウィンドウ関数が使用できるDB(Oracle / PostgreSQL / SQL Server / MySQL 8以降など)では、
よりスマートに記述できます。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
SELECT dept_id, employee, amount FROM ( SELECT dept_id, employee, amount, MAX(amount) OVER (PARTITION BY dept_id) AS max_amount FROM sales ) t WHERE amount = max_amount; |
ポイント
PARTITION BYでグループを定義- 集計しつつ 元の行を保持できる
- JOIN不要で可読性が高い
分析用途や複雑な条件がある場合に特に有効です。
方法④ 最大値の「1件だけ」を取得したい場合
「同率1位が複数ある場合でも、1件だけ欲しい」という場合は
順位付け関数を使用します。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
SELECT dept_id, employee, amount FROM ( SELECT dept_id, employee, amount, ROW_NUMBER() OVER ( PARTITION BY dept_id ORDER BY amount DESC ) AS rn FROM sales ) t WHERE rn = 1; |
ポイント
ROW_NUMBER()は必ず一意になります- 並び順で優先順位を制御できます
- 「代表1件」を取得したい場合に最適です
どの書き方を選ぶべきか
| 要件 | おすすめ |
|---|---|
| 可読性・汎用性重視 | サブクエリ+JOIN |
| 簡潔に書きたい | 相関サブクエリ |
| 分析・拡張性重視 | ウィンドウ関数 |
| 1件だけ取得したい | ROW_NUMBER |
DBの種類やデータ量、可読性を考慮して使い分けることが重要です。
まとめ
MAX()単体では行全体は取得できない- 集計結果と元データを結びつける発想が必要
- 実務では
JOINまたはウィンドウ関数が主流 - 「最大値の行」か「最大値の1件」かを明確にすることが重要
SQLではよく使われるパターンですので、ぜひ覚えておくことをおすすめします。

