Caution

お使いのブラウザはJavaScriptが実行できない状態になっております。
当サイトはWebプログラミングの情報サイトの為、
JavaScriptが実行できない環境では正しいコンテンツが提供出来ません。
JavaScriptが実行可能な状態でご閲覧頂くようお願い申し上げます。

  1. トップページ
  2. SQL辞典
  3. SUM / AVG(ウィンドウ)

SUM / AVG(ウィンドウ)

ウィンドウ関数として使うSUMとAVGは、グループ化せずに累計・移動平均・移動合計などを計算できます。フレーム句と組み合わせることで処理対象の行の範囲を細かく制御できます。

構文
-- 累計(先頭から現在行まで)。
SUM(列名) OVER (
    [PARTITION BY グループ列]
    ORDER BY 並び順列
    ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
)

-- 直近N行の移動平均。
AVG(列名) OVER (
    ORDER BY 並び順列
    ROWS BETWEEN N PRECEDING AND CURRENT ROW
)

-- 全体合計(フレーム句なし・PARTITION BY なし)。
SUM(列名) OVER ()
構文一覧
フレーム句概要
UNBOUNDED PRECEDINGウィンドウ(またはパーティション)の先頭を意味します。
CURRENT ROW現在の行を意味します。
UNBOUNDED FOLLOWINGウィンドウ(またはパーティション)の末尾を意味します。
N PRECEDING現在行のN行前を意味します。
N FOLLOWING現在行のN行後を意味します。
サンプルコード
-- 注文日順の累計売上と全体合計に対する構成比を計算します。
SELECT
    注文日,
    売上金額,
    SUM(売上金額) OVER (
        ORDER BY 注文日
        ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
    ) AS 累計売上,
    SUM(売上金額) OVER () AS 全体合計,
    ROUND(
        売上金額 * 100.0 / SUM(売上金額) OVER (), 1
    ) AS 構成比率
FROM 日別売上
ORDER BY 注文日;

-- 直近3日間の移動平均を計算します。
SELECT
    売上日,
    売上金額,
    AVG(売上金額) OVER (
        ORDER BY 売上日
        ROWS BETWEEN 2 PRECEDING AND CURRENT ROW
    ) AS 直近3日平均
FROM 日別売上
ORDER BY 売上日;

-- 部署ごとの累計給与を計算します。
SELECT
    部署名,
    社員名,
    給与,
    SUM(給与) OVER (
        PARTITION BY 部署名
        ORDER BY 給与 DESC
        ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
    ) AS 部署内累計
FROM 社員
ORDER BY 部署名, 給与 DESC;
実行結果
-- 累計売上と構成比率。
注文日      | 売上金額 | 累計売上 | 全体合計 | 構成比率
------------+----------+----------+----------+---------
2024-01-01  | 120000   | 120000   | 435000   | 27.6
2024-01-02  | 85000    | 205000   | 435000   | 19.5
2024-01-03  | 230000   | 435000   | 435000   | 52.9

-- 直近3日間の移動平均。
売上日      | 売上金額 | 直近3日平均
------------+----------+------------
2024-01-01  | 120000   | 120000.0
2024-01-02  | 85000    | 102500.0
2024-01-03  | 230000   | 145000.0
2024-01-04  | 98000    | 137666.7
データベース別の書き方

ウィンドウ関数としての『SUM()』『AVG()』とフレーム句は MySQL(8.0以降)・PostgreSQL・Oracle・SQL Server・SQLite(3.25以降)で共通して使用できます。

-- 累計売上を計算します(主要データベース共通)。
SELECT
    注文日,
    売上金額,
    SUM(売上金額) OVER (
        ORDER BY 注文日
        ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
    ) AS 累計売上
FROM 日別売上
ORDER BY 注文日;
概要

ウィンドウ関数として使うSUM・AVGは、行数を減らさずに集計値を各行に付与できます。フレーム句でどの行を処理対象にするかを指定することが重要です。

ORDER BY を指定してフレーム句を省略すると、デフォルトのフレームは RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW になります。同じORDER BY値を持つ行はすべて「現在行」とみなされ、意図しない結果になることがあります。明示的に ROWS BETWEEN を指定する習慣をつけましょう。

ウィンドウ関数の基本構文は『OVER / PARTITION BY』を、前後の行参照は『LAG / LEAD』を参照してください。

記事の間違いや著作権の侵害等ございましたらお手数ですがまでご連絡頂ければ幸いです。