一開始你可能會覺得 SQL 已經有夠多分析資料的東西了:GROUP BY、aggregate、subquery... 但這只是個開始。歡迎來到 window functions 的世界 —— 這個超強工具讓你可以 一行一行 處理資料,還能保留全部上下文。
Window functions 讓你可以針對「一個 window 裡的多行」做計算 —— 像是 sum、average、rank 之類的 —— 不用把資料 group 起來。這代表跟一般 aggregate functions(SUM()、AVG()、COUNT())不一樣,你可以在每一行同時看到 結果跟細節。
想像一下你要算每個訂單的累積收入。如果用 GROUP BY,你會看不到每一筆訂單的細節 —— 只剩下總和。但用 window function,你可以直接把結果加到每一行,什麼都不會漏掉。
Window functions 超方便,因為它們不會把資料「壓扁」:每一行都還在原本的位置,計算結果只是加到新的欄位。這樣你就能在一個 query 裡做很複雜的分析,不用 subquery 也不用很醜的結構。這些 function 超適合拿來做排名、算 rolling average 或是比較不同行之間的值。寫出來的 code 很好懂,結果又很精確。
什麼時候特別有用:
- 員工、銷售員、產品的排名 —— 誰排第幾。
- 時間序列 —— 看某個東西每天或每週怎麼變化。
- 銷售跟財務 —— 每一步累積多少、哪些訂單高於平均、誰進入 top 25%。
Window functions 用在哪裡
只要你在意 上下文,不只看總結:
- 銷售報表;
- 客戶行為分析;
- 畫累積指標的圖表;
- 資料分組(像是分四分位數);
- 算偏差跟趨勢。
這些 function 對每天用 SQL 的分析師來說根本是寶藏。 來看幾個真實世界的例子,window functions 怎麼救你一命。
範例 1:資料排名
假設你有一份學生考試成績清單。你想要給每個學生一個班上的名次。用 window functions 超簡單。像 RANK() 或 ROW_NUMBER() 這些 function 就能搞定。
範例 2:時間資料分析
如果你想研究公司每個月的收入怎麼變?你需要 累積收入總和。用 window function 的 SUM() 加上特定 window,馬上就能算出來。
範例 3:分位數跟分組
想把資料分成一樣大的 group(比如照收入分)來 segment 客戶?這時 NTILE() function 就派上用場了。來看看哪些客戶在 top 25%,哪些在排名底部。
長什麼樣子?
Window function 就是直接把結果加到最後的資料集:
SELECT
student_id,
grade,
RANK() OVER (ORDER BY grade DESC) AS rank
FROM
students;
這樣你就會拿到一張表,每個學生都有他自己的成績排名。
簡單比喻
想像你跟一群朋友在跑步。每個人速度都不一樣,但你想知道自己現在排第幾。你不用像 GROUP BY 那樣叫大家停下來做排行榜,你只要看看身邊的人就知道自己目前的名次。
這就是 window function:它不會讓大家停下來,也不會把人分組 —— 它只是加上資訊,大家還是繼續跑,細節都還在。你還可以多拿到一些分析 —— 比如前面有幾個人、你的速度跟平均比怎樣等等。
比傳統方法更強的地方
來看一個經典問題:算銷售員的收入排名。有兩種做法:
不用 window functions。你得寫 subquery,甚至多個 subquery,先排序再編號。又長又難懂。
用 window functions。只要一個 query,語法又漂亮又清楚,結果馬上有。例如:
SELECT
seller_id,
revenue,
RANK() OVER (PARTITION BY region ORDER BY revenue DESC) AS rank_in_region
FROM
sales;
這個 query 直接把銷售員照地區分組,然後依收入高低編號。
真實案例
假設你是分析師,要分析銷售資料。你想知道:
- 每個月的總收入,
- 跟上個月比收入變多少,
- 各地區總收入排名。
這些都可以用 window functions 一次搞定,甚至一個 query 就行。不過這就是下堂課的主題啦。
現在你已經有 window functions 的基本概念,可以開始學它們的語法,還有 ROW_NUMBER()、RANK()、DENSE_RANK() 跟 NTILE() 這些 function 的威力。下一堂課見!
GO TO FULL VERSION