CodeGym /課程 /SQL SELF /用視窗函數計算累積總和: SUM()AVG()

用視窗函數計算累積總和: SUM()AVG()

SQL SELF
等級 29 , 課堂 4
開放

想像一下:你在追蹤你公司的收入、網店的銷售,或是單純分析你一整年的花費。你不只想看到每個月的收入或支出,還想知道這些數字是怎麼一個月一個月累積起來的。

一般的聚合函數(GROUP BY)這時就不夠用了——它們會把資料分組,每組只回傳一行。那如果我們想看到每個月同時又要計算累積總和怎麼辦?這時候就輪到 SUM() 搭配視窗函數出場啦!

用視窗函數計算累積總和的基本用法

視窗函數可以讓你針對視窗範圍做聚合運算。這樣我們就能在每一行上累加數值,但又不會把其他行刪掉。再也不用為了 GROUP BY 犧牲資料啦!

SUM() 搭配視窗函數的語法

這是計算累積總和的基本範本:

SELECT
    column_name,
    SUM(column_name) OVER (PARTITION BY partition_column ORDER BY order_column) AS cumulative_sum
FROM 
    table_name;

這裡:

  • SUM(column_name) — 把數值加總。
  • OVER() — 設定計算的視窗。
  • PARTITION BY — 把資料分組(可選)。
  • ORDER BY — 決定視窗內的排序。

範例:每月累積收入

假設有一張你的收入表:

月份 收入
2023-01 1000
2023-02 1500
2023-03 2000

我們想看到每個月的收入累積到目前為止的總和。來寫個 SQL 查詢:

SELECT
    月份,
    收入,
    SUM(收入) OVER (ORDER BY 月份) AS 累積收入
FROM 
    收入表;

結果:

月份 收入 累積收入
2023-01 1000 1000
2023-02 1500 2500
2023-03 2000 4500

發生了什麼事:

  1. ORDER BY 月份OVER() 裡告訴 PostgreSQL 要照時間順序處理。
  2. 每一行的總和都會包含所有之前的行(還有自己)。

想想這裡的邏輯。第一行 SUM() 只算第一行,第二行算前兩行,第三行算前三行。這就是為什麼月份排序很重要!

範例:各地區累積收入

如果你有一張分地區的銷售表,部分資料可能長這樣:

地區 月份 收入
北部 2023-01 1000
北部 2023-02 1500
南部 2023-01 2000
南部 2023-02 2500

現在我們想分地區計算累積收入:

SELECT
    地區,
    月份,
    收入,
    SUM(收入) OVER (PARTITION BY 地區 ORDER BY 月份) AS 累積收入
FROM 
    銷售表;

結果會是這樣:

地區 月份 收入 累積收入
北部 2023-01 1000 1000
北部 2023-02 1500 2500
南部 2023-01 2000 2000
南部 2023-02 2500 4500

現在每個地區都分開分析(PARTITION BY 地區),但地區內還是照時間排序(ORDER BY 月份)。

移動平均(AVG()

OK,累積總和很酷,但如果你想分析最近三個月的趨勢呢?這時候就要用移動平均啦!

範例:收入的移動平均

我們還是用 收入表,資料如下:

月份 收入
2023-01 1000
2023-02 1500
2023-03 2000
2023-04 2500

計算三個月移動平均的查詢:

SELECT
    月份,
    收入,
    AVG(收入) OVER (
        ORDER BY 月份 
        ROWS BETWEEN 2 PRECEDING AND CURRENT ROW
    ) AS 移動平均
FROM 
    收入表;

結果:

月份 收入 移動平均
2023-01 1000 1000
2023-02 1500 1250
2023-03 2000 1500
2023-04 2500 2000

說明:

  1. ROWS BETWEEN 2 PRECEDING AND CURRENT ROW 告訴 PostgreSQL 要看當前行和前兩行來算平均。
  2. 所以每個月都會看到最近三個月的平均收入。

也就是說,每一行都設定一個三行的視窗:自己加上前兩行,然後計算平均。超方便!

ORDER BY 的作用與影響

視窗函數很吃排序。如果排序錯了(或根本沒排序),結果可能會很奇怪。

範例:沒加 ORDER BY 的錯誤

如果我們把 OVER() 裡的 ORDER BY 拿掉,累積總和就會變成每行都顯示全部收入的總和:

SELECT
    月份,
    收入,
    SUM(收入) OVER () AS 錯誤累積總和
FROM 
    收入表;

結果:

月份 收入 錯誤累積總和
2023-01 1000 7000
2023-02 1500 7000
2023-03 2000 7000
2023-04 2500 7000

行沒有排序,結果就是每行都直接加總所有收入,完全沒分別。

真實使用案例

收入分析

  • 累積總和可以追蹤公司銷售或收入的成長。
  • 移動平均能讓你看到「乾淨」的趨勢,不會被雜訊干擾。

財務建模

銀行和金融公司會用視窗函數來分析還款、債務成長等指標。

時間序列分析

像是線上用戶數、頁面瀏覽量、營收等等時間資料,用 SUM()AVG() 來分析超級適合。

2
任務
SQL SELF, 等級 29, 課堂 4
上鎖
最近三個月的移動平均
最近三個月的移動平均
1
問卷/小測驗
視窗函式,等級 29,課堂 4
未開放
視窗函式
視窗函式
留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION