2025年11月7日金曜日

SQL Server ウィンドウ関数(OVER句)の基本と実務活用|ROW_NUMBER・RANK・SUMで理解する分析関数入門

SQL Server ウィンドウ関数(OVER句)の基本と実務活用について

SQL Serverでの分析処理やランキング集計を効率化する強力な機能が、ウィンドウ関数(OVER句)です。
従来はサブクエリや自己結合で複雑に書いていた処理を、1つのクエリで簡潔に実現できます。
本記事では、ウィンドウ関数の基本構文から代表的な関数(ROW_NUMBER、RANK、SUMなど)の使い方、実務での応用例までを初心者向けに解説します。

目次

ウィンドウ関数とは?基本の考え方

通常の集計との違い

通常のGROUP BY集計では、グループ化された単位ごとに1行の結果しか返りません。
一方、ウィンドウ関数は「集計しつつ元の行も残す」ことができます。
つまり、明細を保持したまま集計結果(例:順位・累計・平均)を表示できます。

この「行を消さない集計」が、ウィンドウ関数の最大の特徴です。

基本構文


関数名(...) OVER (
  [PARTITION BY 列名]
  [ORDER BY 列名]
)

この構文の中で、PARTITION BY は「グループ分け」、ORDER BY は「並び順」を指定します。
どちらも省略可能ですが、ウィンドウの範囲を意識することで正確な分析ができます。

OVER句の構文とPARTITION BY/ORDER BYの意味

PARTITION BY:グループを分けて計算する

PARTITION BY を使うと、指定した列単位で集計をリセットできます。
たとえば「社員ごとの売上順位」を求めたいときに便利です。


SELECT EmployeeID,
       OrderID,
       SalesAmount,
       RANK() OVER(PARTITION BY EmployeeID ORDER BY SalesAmount DESC) AS 社員内順位
FROM Sales;

このSQLでは、EmployeeIDごとに売上金額の順位を出しています。

ORDER BY:順序を定義して並び替える

ORDER BY は、順位関数(RANK、ROW_NUMBERなど)や累計(SUM、AVGなど)の順序を決定します。
指定がない場合、結果の順序は保証されません。


SELECT OrderID,
       CustomerID,
       SUM(SalesAmount) OVER(ORDER BY OrderDate) AS 売上累計
FROM Sales;

この例では、注文日の昇順に売上累計を計算します。

代表的なウィンドウ関数の使い方

ROW_NUMBER:連番を振る

ROW_NUMBER() は、指定した順序で1から順に連番を振る関数です。


SELECT ROW_NUMBER() OVER(ORDER BY OrderDate) AS 行番号,
       OrderID, CustomerID, OrderDate
FROM Sales;

ORDER BY を変更すれば、並び替えに応じた通し番号を振ることもできます。
ページング処理や最新データの抽出によく使われます。

RANK と DENSE_RANK:順位をつける

RANK() は順位を付けますが、同順位がある場合は次の順位が飛びます。
DENSE_RANK() は順位が詰まります。


SELECT ProductID,
       SalesAmount,
       RANK() OVER(ORDER BY SalesAmount DESC) AS RANK順位,
       DENSE_RANK() OVER(ORDER BY SalesAmount DESC) AS DENSE順位
FROM Sales;

売上順位などで「同点順位」を表現する場合に非常に便利です。

SUM と AVG:累計・平均を出す

SUM や AVG に OVER句を組み合わせることで、行ごとの累計や移動平均を求めることができます。


SELECT OrderDate,
       SUM(SalesAmount) OVER(ORDER BY OrderDate) AS 売上累計,
       AVG(SalesAmount) OVER(ORDER BY OrderDate) AS 平均売上
FROM Sales;

このように、明細行を保持したまま集計結果を一緒に出せるのがウィンドウ関数の強みです。

実務で使える応用例

例1:月ごとの売上ランキング


SELECT FORMAT(OrderDate, 'yyyy-MM') AS 月,
       ProductID,
       SUM(SalesAmount) AS 月間売上,
       RANK() OVER(PARTITION BY FORMAT(OrderDate, 'yyyy-MM')
                   ORDER BY SUM(SalesAmount) DESC) AS 月内順位
FROM Sales
GROUP BY FORMAT(OrderDate, 'yyyy-MM'), ProductID;

月単位で集計した売上に順位をつけることで、人気商品ランキングを簡単に出せます。

例2:社員ごとの累計売上


SELECT EmployeeID,
       OrderDate,
       SUM(SalesAmount) OVER(PARTITION BY EmployeeID ORDER BY OrderDate) AS 累計売上
FROM Sales;

PARTITION BYを使うことで、社員ごとの進捗を可視化できます。

例3:最新データを1件だけ取得(ROW_NUMBER活用)


WITH Ranked AS (
  SELECT CustomerID, OrderID, OrderDate,
         ROW_NUMBER() OVER(PARTITION BY CustomerID ORDER BY OrderDate DESC) AS rn
  FROM Orders
)
SELECT CustomerID, OrderID, OrderDate
FROM Ranked
WHERE rn = 1;

このクエリで「各顧客の最新注文だけ」を簡単に抽出できます。

ウィンドウ関数を使うときの注意点

1. パフォーマンスに注意

ORDER BYを含むウィンドウ関数は、並び替え処理が発生するためデータ量が多いと負荷がかかります。
必要な列だけをSELECTし、インデックスを活用しましょう。

2. GROUP BYとの違いを理解する

GROUP BYは「グループ化して1行にまとめる」、ウィンドウ関数は「グループ内で集計しつつ明細を残す」ものです。
用途を混同しないように注意が必要です。

3. OVER句を省略できる関数もある

ROW_NUMBER、RANK、DENSE_RANKなどは必ずOVER句を指定しますが、集計関数を使う場合はORDER BYを省略するとグループ全体に対して計算されます。

まとめと次のステップ

学んだ内容の整理

  • ウィンドウ関数は「明細を残したまま集計する」便利な仕組み。
  • OVER句で集計範囲(PARTITION BY)と順序(ORDER BY)を制御できる。
  • ROW_NUMBERで連番、RANKで順位、SUMやAVGで累計や平均を算出可能。
  • 実務ではランキング・累計・最新データ抽出などに多用される。

参考リンク

SQL Server 解説用イメージ

0 件のコメント:

コメントを投稿