言語
日本語
English

Caution

お使いのブラウザはJavaScriptが無効になっております。
当サイトでは検索などの処理にJavaScriptを使用しています。
より快適にご利用頂くため、JavaScriptを有効にしたうえで当サイトを閲覧することをお勧めいたします。

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

SUM / AVG(ウィンドウ)

対応: SQL:2003(2003)

ウィンドウ関数として使う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
)

grand_total(フレーム句なし・PARTITION BY なし)です。

SUM(列名) OVER ()

構文一覧

フレーム句概要
UNBOUNDED PRECEDINGウィンドウ(またはパーティション)の先頭を意味します。
CURRENT ROW現在の行を意味します。
UNBOUNDED FOLLOWINGウィンドウ(またはパーティション)の末尾を意味します。
N PRECEDING現在行のN行前を意味します。
N FOLLOWING現在行のN行後を意味します。

サンプルコード

以下の『daily_sales』テーブルを例に説明します。

daily_sales order_date amount 2024-01-01 120000 2024-01-02 85000 2024-01-03 230000 2024-01-04 98000 4 rows in set

order_date順のrunning_totalとgrand_totalに対する構成比を計算します。

sample_sum_avg_window.sql
SELECT
    order_date,
    amount,
    SUM(amount) OVER (
        ORDER BY order_date
        ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
    ) AS running_total,
    SUM(amount) OVER () AS grand_total,
    ROUND(
        amount * 100.0 / SUM(amount) OVER (), 1
    ) AS pct_of_total
FROM daily_sales
ORDER BY order_date;
+------------+----------+----------+----------+----------+
| order_date     | amount | running_total | grand_total | pct_of_total |
+------------+----------+----------+----------+----------+
| 2024-01-01 |   120000 |   120000 |   533000 |     22.5 |
| 2024-01-02 |    85000 |   205000 |   533000 |     15.9 |
| 2024-01-03 |   230000 |   435000 |   533000 |     43.2 |
| 2024-01-04 |    98000 |   533000 |   533000 |     18.4 |
+------------+----------+----------+----------+----------+
4 rows in set

直近3日間の移動平均を計算します。

sample_sum_avg_window.sql
SELECT
    order_date,
    amount,
    AVG(amount) OVER (
        ORDER BY order_date
        ROWS BETWEEN 2 PRECEDING AND CURRENT ROW
    ) AS moving_avg_3d
FROM daily_sales
ORDER BY order_date;
+------------+----------+-------------+
| order_date     | amount | moving_avg_3d |
+------------+----------+-------------+
| 2024-01-01 |   120000 |  120000.000 |
| 2024-01-02 |    85000 |  102500.000 |
| 2024-01-03 |   230000 |  145000.000 |
| 2024-01-04 |    98000 |  137666.667 |
+------------+----------+-------------+
4 rows in set

直近2日間の移動合計を計算します。

sample_sum_avg_window.sql
SELECT
    order_date,
    amount,
    SUM(amount) OVER (
        ORDER BY order_date
        ROWS BETWEEN 1 PRECEDING AND CURRENT ROW
    ) AS moving_sum_2d
FROM daily_sales
ORDER BY order_date;
+------------+----------+-------------+
| order_date     | amount | moving_sum_2d |
+------------+----------+-------------+
| 2024-01-01 |   120000 |      120000 |
| 2024-01-02 |    85000 |      205000 |
| 2024-01-03 |   230000 |      315000 |
| 2024-01-04 |    98000 |      328000 |
+------------+----------+-------------+
4 rows in set

データベース別の書き方

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

SELECT
    order_date,
    amount,
    SUM(amount) OVER (
        ORDER BY order_date
        ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
    ) AS running_total
FROM daily_sales
ORDER BY order_date;

概要

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

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

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

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