データベーススペシャリスト試験や応用情報技術者試験の午後問題で頻出の「ウィンドウ関数」。SQLの上級者向け機能でありながら、「そもそも何が“ウィンドウ”なの?」「GROUP BYとの違いがいまいち分からない」と感じる方も多いのではないでしょうか。
実務では売上ランキングの計算や累積値の集計、人事評価の並び替えなど、データの“部分的な集計”が必要な場面でウィンドウ関数は非常に強力なツールになります。しかし、その「直感的に分かりにくい概念性」が、学習のハードルを上げているのも事実です。
この記事では、ウィンドウ関数とは何か、なぜ“ウィンドウ”という名前がついているのかといった語源・概念の理解から始め、試験で狙われやすい出題パターンやよくある引っかけポイントまでを、図解・具体例・比喩を交えて体系的に解説します。
PARTITION BY と GROUP BY の混同を解きほぐしながら、「なぜそれが必要なのか」まで腹落ちさせることを目指します。
目次
ウィンドウ関数の語源と基本概念│なぜ“ウィンドウ”なのかを図解で理解する
SQLにおける「ウィンドウ関数」とは、行ごとの計算において“集計の枠(ウィンドウ)”を指定して処理を行う関数のことです。
例えば「各部署ごとの給与順位」や「各月ごとの累積売上」など、全体ではなく“ある範囲内”での集計を行いたいときに使われます。
🔍 なぜ「ウィンドウ」なのか?
“ウィンドウ(window)”とは、日本語で言う「窓」ではなく、「範囲」「枠組み」の意味です。
つまり、ウィンドウ関数は「ある範囲(枠)を定義し、その中で集計・順位付けなどを行う」機能なのです。
📊 図解:通常の集計 vs ウィンドウ関数
| ID | 部署 | 給与 | 部署内順位(ウィンドウ関数) |
|---|---|---|---|
| 1 | 営業 | 300 | 2 |
| 2 | 営業 | 500 | 1 |
| 3 | 総務 | 280 | 2 |
| 4 | 総務 | 340 | 1 |
→ これは RANK() OVER (PARTITION BY 部署 ORDER BY 給与 DESC) によって、部署ごとに給与を並び替えた例です。
GROUP BY では「営業」「総務」それぞれ1行にしかならず、このような行単位の情報保持と集計の併用はできません。
💡 ここで追加質問:
「GROUP BY でも集計できるなら、なぜわざわざウィンドウ関数を使うの?」
次セクションではこの疑問を解決します!
GROUP BYとの違いとPARTITION BYの意味│ウィンドウ関数の“部分集計”を直感的に理解する
SQL初学者がウィンドウ関数で最も混乱しやすいのが、「GROUP BYとどう違うの?」という点です。
結論から言えば、GROUP BYは“行をまとめる”集計、PARTITION BYは“まとめずに、範囲を指定して集計”する機能です。
🧠 比喩で理解:「GROUP BYは集団写真、PARTITION BYは名簿の横にメモ」
- GROUP BY:各部署の代表を1人ずつ並べて、集合写真を撮る →「1部署=1行」のデータになる
- PARTITION BY:全社員が名簿に並んだまま、横に「この人は部署内で何位」などメモを書き加える → 行数はそのまま!
🔍 実例比較:GROUP BY vs ウィンドウ関数
テーブル例(社員データ)
| ID | 部署 | 給与 |
|---|---|---|
| 1 | 営業 | 300 |
| 2 | 営業 | 500 |
| 3 | 総務 | 280 |
| 4 | 総務 | 340 |
📌 GROUP BY を使った場合
SELECT 部署, AVG(給与) FROM 社員 GROUP BY 部署;
| 部署 | 平均給与 |
|---|---|
| 営業 | 400 |
| 総務 | 310 |
→ 「部署ごとに集計」して、行数が部署数に減る
📌 ウィンドウ関数(PARTITION BY)を使った場合
SELECT *, AVG(給与) OVER (PARTITION BY 部署) AS 部署別平均
FROM 社員;
| ID | 部署 | 給与 | 部署別平均 |
|---|---|---|---|
| 1 | 営業 | 300 | 400 |
| 2 | 営業 | 500 | 400 |
| 3 | 総務 | 280 | 310 |
| 4 | 総務 | 340 | 310 |
→ 行数は変わらず、集計結果を“追加情報として横に貼る”のがウィンドウ関数の特徴です。
✔ POINT:GROUP BYとPARTITION BYの違いまとめ表
| 比較軸 | GROUP BY | PARTITION BY(ウィンドウ関数) |
|---|---|---|
| 行数 | 減る(グループ単位になる) | 変わらない(全行を保持) |
| 表示できる列 | GROUP列か集計列のみ | すべての列をそのまま表示可能 |
| 用途 | グループごとの集計 | 行単位の集計+元の情報の同時表示 |
ウィンドウ関数の使いどころとNG例│試験や実務で使われるパターンと避けるべきケース
ウィンドウ関数は非常に柔軟な機能ですが、「何でもウィンドウ関数で済ませればいい」というわけではありません。
このセクションでは、よく使われる代表的な場面と、逆に使わない方が適切なケースをセットで紹介します。
✅ よく使われるシーン(試験にも頻出)
| シーン | 内容 | 具体例 |
|---|---|---|
| ランキング付け | 同順位の扱いや行ごとの順位表示が必要 | RANK() / ROW_NUMBER() |
| 累積集計 | 日別・月別に積み上げていくデータ処理 | SUM() OVER (ORDER BY 日付) |
| 部分平均 | カテゴリごとに平均・最大・最小を出す | AVG() OVER (PARTITION BY カテゴリ) |
| 前後比較 | 前月比・前年差分など | LAG() / LEAD() |
🔍 試験に出やすい組み合わせパターン
- PARTITION BY + ORDER BY:集計対象と並び順を明示
- RANK vs ROW_NUMBER:同値の扱いで結果が異なる
- LAG/LEAD の OFFSET:前行・後行が存在しないときの NULL 処理が問われる
⚠ ウィンドウ関数を避けた方がいいケース
| ケース | 理由 | 代替案 |
|---|---|---|
| データ件数が膨大 | ウィンドウ関数は重い。パフォーマンス悪化 | サマリテーブル or 一時テーブル |
| シンプルな合計だけでよい | GROUP BY の方が読みやすく軽い | 通常の GROUP BY |
| データ結合(JOIN)を優先すべきとき | ウィンドウ関数より JOIN の方が意味が明確 | サブクエリ + JOIN |
💡 POINT:試験では“使うべきか見極める力”が問われる
午後試験では、必ずしも「ウィンドウ関数を使え」という意図ではなく、「最適な手段を選べるか?」がポイントです。
そのため、「すべてをウィンドウ関数で解決しよう」とするのではなく、「これはGROUP BYの方が適切では?」という視点も重要です。
午後試験で狙われるSQLキーワードとウィンドウ関数の連携パターン
IPAのデータベース系試験では、「ウィンドウ関数そのもの」よりも、「ウィンドウ関数+他のSQL構文」の組み合わせパターンで問われるケースが多く見られます。
ここでは試験に頻出するキーワードと、ウィンドウ関数との“連動関係”を具体的に紹介します。
✅ 試験でよく出るSQLキーワードと使い方
| キーワード | 連動ポイント | ウィンドウ関数との関連例 |
|---|---|---|
OVER |
ウィンドウ関数の本体部分 | SUM() OVER (...) など |
PARTITION BY |
グループ分け | カテゴリや部署単位の計算 |
ORDER BY(OVER句内) |
並び順指定 | 累積、ランキング系の正確な計算に必要 |
RANK() / ROW_NUMBER() |
順位の算出 | 並び替え・重複の扱いに違いあり |
LAG() / LEAD() |
前後の値の参照 | 前回との差分、遷移検出など |
CASE |
条件による振り分け | ウィンドウ関数の結果をもとに条件分岐 |
🔍 具体的な連携パターン例
① 累積売上をカテゴリ別に計算
SELECT 商品カテゴリ, 売上日, 売上金額,
SUM(売上金額) OVER (PARTITION BY 商品カテゴリ ORDER BY 売上日) AS 累積売上
FROM 売上データ;
→ カテゴリごとに日付順で売上を積み上げる処理。ORDER BY の重要性が問われやすい
② 前回との差分を出す(LAGとの組み合わせ)
SELECT 社員ID, 月, 勤怠時間,
勤怠時間 - LAG(勤怠時間) OVER (PARTITION BY 社員ID ORDER BY 月) AS 増減
FROM 勤怠記録;
→ LAG関数と演算を組み合わせるパターンは頻出。NULL考慮の選択肢もよく出題される。
③ ランキングで上位3位までを抽出(RANK + サブクエリ)
SELECT * FROM (
SELECT 社員ID, 部署, 給与,
RANK() OVER (PARTITION BY 部署 ORDER BY 給与 DESC) AS 順位
FROM 社員
) AS ランク付け
WHERE 順位 <= 3;
→ 部署ごとに給与順位を付けて「上位3人のみ」を抽出。RANK関数+サブクエリがよく使われる。
④ 最新月の値と過去月の差を比較(LEAD+日付条件)
SELECT 商品ID, 月, 売上,
売上 - LEAD(売上) OVER (PARTITION BY 商品ID ORDER BY 月 DESC) AS 前月比
FROM 売上データ;
→ LEAD関数と演算を組み合わせたパターン。ORDER BY の DESC 指定に注意。
⑤ 条件に応じて集計対象を切り替える(CASE+ウィンドウ関数)
SELECT 社員ID, 勤務区分, 勤務時間,
SUM(CASE WHEN 勤務区分 = '通常' THEN 勤務時間 ELSE 0 END)
OVER (PARTITION BY 社員ID ORDER BY 日付) AS 通常勤務累積
FROM 勤怠記録;
→ CASEで条件分岐した累積集計。試験では「条件に応じた集計」が頻出です。
💡 試験対策のコツ
- OVER句の中身を読めば、何が起きているか分かるようになる
- ORDER BYがないと、期待通りに並ばない=減点されやすい
- RANK系とROW_NUMBERの違いに着目せよ
試験でのひっかけポイントと間違えやすい落とし穴│ウィンドウ関数の誤用に注意
午後試験では、ウィンドウ関数の「基本的な書き方」よりも、“微妙な違いによる誤答”を誘う選択肢が多く出題されます。
ここでは、受験生がつまずきやすいポイントや、よくあるミスを整理します。
❗ よくある間違いとその原因
| ミス例 | 原因 | 正しい理解 |
|---|---|---|
OVER に ORDER BY を書き忘れる |
デフォルトの並びで集計され、順位や累積結果が想定外になる | 並び順は常に意識して指定する |
PARTITION BY を使い忘れる |
全体で集計されてしまい、「部署ごとの平均」などが破綻 | 必要な単位ごとに区切る |
RANK() と ROW_NUMBER() の使い分けミス |
同順位あり/なしで結果が大きく変わる | 問題の意図を確認して選択する |
LAG() の NULL を考慮しない |
初回の行で差分計算が崩れる | COALESCE() などで補う処理が必要な場合あり |
📌 試験でよく出る“ひっかけポイント”
- PARTITION BY の指定があるか・ないかの違いを読み落とさせる
- ORDER BY の順序(ASC / DESC)で意味が逆転する選択肢
- RANK系の数値のズレに着目できるか
- NULLに対する理解(初行のLAG/LEADの扱い)を問う設問
✅ 回避のためのチェックリスト
- OVER句の中に
PARTITION BYとORDER BYが適切にあるか? - 集計対象の粒度は正しいか(部署単位、日付単位など)?
- 順位の扱い(同順位あり/なし)は設問に合っているか?
- NULLが返る可能性のある関数に対して補正が必要か?
コラム:集計関数とGROUP BY、そしてウィンドウ関数の真価
SQLを学んでいて混乱しやすいのが「集計関数とGROUP BYの関係」と「ウィンドウ関数におけるPARTITION BY・ORDER BYの役割」です。最後に整理しておきましょう。
前提:元データ
以下の売上テーブルを例に説明します。
| 日付 | 部署 | 名前 | 売上 |
|---|---|---|---|
| 2025-09-01 | 営業 | 田中 | 100 |
| 2025-09-02 | 営業 | 鈴木 | 150 |
| 2025-09-03 | 開発 | 佐藤 | 200 |
| 2025-09-04 | 開発 | 山田 | 50 |
集計関数とGROUP BYの関係
SELECT 部署, SUM(売上)
FROM 売上テーブル
GROUP BY 部署;
結果
| 部署 | SUM(売上) |
|---|---|
| 営業 | 250 |
| 開発 | 250 |
ウィンドウ関数と PARTITION BY / ORDER BY
SELECT
部署,
名前,
売上,
SUM(売上) OVER (PARTITION BY 部署) AS 部署合計,
SUM(売上) OVER (PARTITION BY 部署 ORDER BY 日付) AS 部署累計
FROM 売上テーブル;
結果
| 部署 | 名前 | 売上 | 部署合計 | 部署累計 |
|---|---|---|---|---|
| 営業 | 田中 | 100 | 250 | 100 |
| 営業 | 鈴木 | 150 | 250 | 250 |
| 開発 | 佐藤 | 200 | 250 | 200 |
| 開発 | 山田 | 50 | 250 | 250 |
OVER() のかっこ内が空のとき
SELECT
日付,
名前,
売上,
SUM(売上) OVER () AS 総売上
FROM 売上テーブル;
結果
| 日付 | 名前 | 売上 | 総売上 |
|---|---|---|---|
| 2025-09-01 | 田中 | 100 | 500 |
| 2025-09-02 | 鈴木 | 150 | 500 |
| 2025-09-03 | 佐藤 | 200 | 500 |
| 2025-09-04 | 山田 | 50 | 500 |
LAG / LEAD での前後比較
SELECT
日付,
名前,
売上,
LAG(売上, 1) OVER (ORDER BY 日付) AS 前日売上,
LEAD(売上, 1) OVER (ORDER BY 日付) AS 翌日売上
FROM 売上テーブル;
結果
| 日付 | 名前 | 売上 | 前日売上 | 翌日売上 |
|---|---|---|---|---|
| 2025-09-01 | 田中 | 100 | NULL | 150 |
| 2025-09-02 | 鈴木 | 150 | 100 | 200 |
| 2025-09-03 | 佐藤 | 200 | 150 | 50 |
| 2025-09-04 | 山田 | 50 | 200 | NULL |
RANK による順位付け
SELECT
名前,
売上,
RANK() OVER (ORDER BY 売上 DESC) AS 売上順位
FROM 売上テーブル;
結果
| 名前 | 売上 | 売上順位 |
|---|---|---|
| 佐藤 | 200 | 1 |
| 鈴木 | 150 | 2 |
| 田中 | 100 | 3 |
| 山田 | 50 | 4 |
【重要】RANK の ORDER BY は OVER() の内側に必要
外側(SELECT の最後)の ORDER BY はあくまで「表示順」を決めるだけで、順位の計算には影響しません。
順位の基準は必ず OVER(ORDER BY ...) の内側で指定します。
ROW_NUMBER による連番付与
SELECT
名前,
売上,
ROW_NUMBER() OVER (ORDER BY 売上 DESC) AS 行番号
FROM 売上テーブル;
結果
| 名前 | 売上 | 行番号 |
|---|---|---|
| 佐藤 | 200 | 1 |
| 鈴木 | 150 | 2 |
| 田中 | 100 | 3 |
| 山田 | 50 | 4 |
【注意】ROW_NUMBER の順序保証
ROW_NUMBER() はユニークな連番を振りますが、どの順番で番号が付くかは OVER(ORDER BY ...) の内側に書かないと保証されません。
もし OVER() を空にして外側にだけ ORDER BY を書いた場合、表示順は並び替えられても、番号の付与順序は内部処理依存となり、環境や実行計画によって変わる危険があります。
👉 したがって、必ず OVER 内の ORDER BY で順序を指定するのが正しい書き方です。
コラムまとめ
- 集計関数+GROUP BY:行をまとめて短くする(グループの数だけ出力)
- ウィンドウ関数+OVER():行を残したまま「全体の集計結果」を列として追加
- ウィンドウ関数+PARTITION BY:行を残したまま「グループ単位の情報」を列として追加
- ウィンドウ関数+ORDER BY:順序依存の計算(累計、LAG/LEAD、順位付け、連番付け)を可能にする
- RANK / ROW_NUMBER の ORDER BY は OVER 内に必須(外側の ORDER BY は表示順だけを制御)
ウィンドウ関数を使えば、「集計」「比較」「順位付け」「連番付け」を、元の行を保持したまま自在に組み合わせられます。
まとめ│ウィンドウ関数を“理解して使える”技術にするために
ウィンドウ関数は「ただのSQL関数の一種」と捉えると難解ですが、「部分集計のための“窓”を開く道具」と考えることで、実務でも試験でも強力な武器になります。
この記事で紹介したように、GROUP BY との違いや PARTITION BY・ORDER BY の正しい使い方、LAG/LEAD などとの組み合わせパターンを押さえることが、午後試験対策の要になります。
- ウィンドウ関数は「集計+詳細の同時表示」が得意
- GROUP BY では実現できない“行ごとの相対処理”を補える
- 試験では「微妙な指定漏れ」による誤答を誘う問題に注意
単なる丸暗記ではなく、概念を直感的に理解し、適切な場面で使いこなす力を身につけることが、スコアアップへの近道です。