SQL で、月別の累計と前年同月比を出す(ウィンドウ関数と、月が欠けたときの落とし穴)
濵口 翔長崎で、Power BI のつまずきを記録しています確認日2026年10月21日。
PostgreSQL 16.13(Docker の コンテナ)で、 疑似データを 使って、 実際に 動かして 確かめました。疑似データです。 実在の 確認できていない店舗や 売上ではありません。 ことは、 末尾に まとめました。
月別のSUM(...) OVER、LAG(..., 12) でLAG は
結論
(30秒版)
- 累計は、
SUM(amt) OVER (ORDER BY month)で出ました。 年ごとに リセットする 年内累計は、 PARTITION BYに年を 入れます。 - 前年同月比は、
LAG(amt, 12) OVER (ORDER BY month)で出ました。 - 途中の
月が 月が欠けると、 LAG(12)は、12行前の 別の 月を 返しました。 欠けうる データでは、 結合で 前年同月を 取る 方が 安全でした。
使ったデータ
前のm と
WITH m AS (
SELECT date_trunc('month', sale_date)::date AS month, SUM(amount) AS amt
FROM sales GROUP BY 1
)
累計
SELECT month, amt, SUM(amt) OVER (ORDER BY month) AS running_total
FROM m ORDER BY month;
2024年12月から
| month | amt | running_total |
|---|---|---|
| 2024-12-01 | 135282 | 1588842 |
| 2025-01-01 | 151512 | 1740354 |
| 2025-02-01 | 137928 | 1878282 |
OVER (ORDER BY month) が、
年内累計(年ごとにリセット)
SELECT month, amt,
SUM(amt) OVER (PARTITION BY date_trunc('year', month) ORDER BY month) AS ytd
FROM m ORDER BY month;
| month | amt | ytd |
|---|---|---|
| 2024-12-01 | 135282 | 1588842 |
| 2025-01-01 | 151512 | 151512 |
| 2025-02-01 | 137928 | 289440 |
2025年1月で、PARTITION BY が、
前年同月比(LAG)
SELECT month, amt,
LAG(amt, 12) OVER (ORDER BY month) AS prev_year,
ROUND(100.0 * amt / LAG(amt, 12) OVER (ORDER BY month), 1) AS pct_of_prev
FROM m ORDER BY month;
2025年1月から
| month | amt | prev_year | pct_of_prev |
|---|---|---|---|
| 2025-01-01 | 151512 | 132912 | 114.0 |
| 2025-02-01 | 137928 | 125748 | 109.7 |
| 2025-03-01 | 152550 | 133632 | 114.2 |
LAG(amt, 12) は、
落とし穴: 月が欠けると、ずれる
2024年6月のm には、
実際に、LAG(12) を
| month | amt | prev_by_lag | lag_month |
|---|---|---|---|
| 2025-06-01 | 150390 | 128634 | 2024-05-01 |
| 2025-07-01 | 152454 | 133536 | 2024-07-01 |
2025年6月の
結合で前年同月を取る
月の
SELECT c.month, c.amt, p.amt AS prev_year
FROM m c
LEFT JOIN m p ON p.month = (c.month - interval '1 year')::date
ORDER BY c.month;
同じ
| month | amt | prev_year |
|---|---|---|
| 2025-06-01 | 150390 | (NULL) |
| 2025-07-01 | 152454 | 133536 |
前年のNULL にLEFT JOIN をJOIN に
使い分け
- 月が、
必ず すべて 揃っている (カレンダーテーブルが ある、 など)なら、 LAG(12)は、短く 書けて 分かりやすいです。 - 月が
欠けるかもしれないなら、 結合で 取る方が 安全です。
Power BI の
この記事で確認できたこと・できていないこと
確認日: 2026年10月21日。
確認できた
SUM(...) OVER (ORDER BY ...)で、年を またぐ 累計が 出る こと PARTITION BYに年を 入れると、 年ごとに リセットされる こと LAG(..., 12)で、前年同月の 値と 比が 出る こと - 月が
1つ欠けると、 LAG(12)は、その 月の 前後で、 別の 月の 値を 返す こと (2025年6月に、 2024年5月の 値) - 結合で
取ると、 前年の ない 月は NULLになる こと
確認できていない
- 日次や
週次の データでの 前年比(うるう年の 2月29日の 扱いなど ) - PostgreSQL 以外の
データベースでの 書き方の 違い - 大きな
データでの 速さ - Power BI が
発行する SQL との 対応 - 公式ドキュメントとの
照合