☕ NEW! 完成新手任務即可參加抽獎!LINE 星巴克禮券等你拿,名額有限!        🎉 推廣活動:邀請好友註冊 DevLearn,累積推薦抽 LINE 星巴克禮券! 活動詳情 →        🔥 活動期間 2026/4/1 - 5/31 |已有 0 人參加       
sql 進階

Window Functions 視窗函數

什麼是 Window Function?

比喻:Window Function 就像站在教室門口看全班 🪟

GROUP BY 把全班打散到各個小房間,你只能看到自己那間的統計。 Window Function 讓你站在門口,既能看到自己的分數,也能看到全班的統計。

Window Function 在不縮減列數的情況下做統計計算。


GROUP BY vs Window Function

-- GROUP BY:每組一列(原始資料被壓縮)
SELECT Department, AVG(Score)
FROM Students
GROUP BY Department;
-- 結果只有 3 列(3 個科系)

-- Window Function:保留每一列,加上統計欄位
SELECT
    Name,
    Department,
    Score,
    AVG(Score) OVER (PARTITION BY Department) AS 系平均
FROM Students;
-- 結果還是 30 列(每個學生一列),但多了系平均欄位

OVER() 基本語法

SELECT
    Name,
    Score,
    AVG(Score) OVER () AS 全班平均,       -- ← OVER() 空的 = 全體
    Score - AVG(Score) OVER () AS 差距    -- ← 每人與平均的差距
FROM Students;

結果:

 Name | Score | 全班平均 | 差距
------+-------+---------+------
 小明 |    85 |   75.0  | 10.0
 小華 |    78 |   75.0  |  3.0
 小美 |    62 |   75.0  | -13.0

PARTITION BY — 分組窗口

SELECT
    Name,
    Department,
    Score,
    AVG(Score) OVER (PARTITION BY Department) AS 系平均,
    MAX(Score) OVER (PARTITION BY Department) AS 系最高分,
    Score - AVG(Score) OVER (PARTITION BY Department) AS 與系平均差距
FROM Students;
PARTITION BY Department  -- 按科系分窗口
                         -- 每個學生都能看到「自己科系」的統計
                         -- 但不會把資料壓縮成一列

ROW_NUMBER、RANK、DENSE_RANK

SELECT
    Name,
    Score,
    ROW_NUMBER() OVER (ORDER BY Score DESC) AS 序號,
    RANK()       OVER (ORDER BY Score DESC) AS 排名,
    DENSE_RANK() OVER (ORDER BY Score DESC) AS 密集排名
FROM Students;

結果(假設有同分情況):

 Name | Score | 序號 | 排名 | 密集排名
------+-------+------+------+---------
 小明 |    95 |    1 |    1 |       1
 小華 |    90 |    2 |    2 |       2
 小美 |    90 |    3 |    2 |       2   ← RANK 同分同名次
 小剛 |    85 |    4 |    4 |       3   ← RANK 跳 4,DENSE_RANK 接 3
函數 同分處理 下一名
ROW_NUMBER 不同分(1,2,3,4) 接續
RANK 同分(1,2,2,4) 跳號
DENSE_RANK 同分(1,2,2,3) 接續

分組排名

-- 每個科系中的排名
SELECT
    Name,
    Department,
    Score,
    RANK() OVER (
        PARTITION BY Department      -- ← 每個科系各自排
        ORDER BY Score DESC          -- ← 分數高到低
    ) AS 系內排名
FROM Students;
-- 只取每科系前 3 名
WITH ranked AS (
    SELECT *, RANK() OVER (PARTITION BY Department ORDER BY Score DESC) AS rk
    FROM Students
)
SELECT * FROM ranked WHERE rk <= 3;

LAG / LEAD — 前後列

SELECT
    Name,
    Score,
    LAG(Score, 1) OVER (ORDER BY Score DESC) AS 前一名分數,
    LEAD(Score, 1) OVER (ORDER BY Score DESC) AS 後一名分數,
    Score - LAG(Score, 1) OVER (ORDER BY Score DESC) AS 與前一名差距
FROM Students;
LAG(Score, 1)   -- 往前看 1 列的 Score(上一名的分數)
LEAD(Score, 1)  -- 往後看 1 列的 Score(下一名的分數)

SUM / AVG 的窗口累計

-- 累計營業額
SELECT
    OrderDate,
    Amount,
    SUM(Amount) OVER (ORDER BY OrderDate) AS 累計營業額,
    AVG(Amount) OVER (ORDER BY OrderDate) AS 滾動平均
FROM Orders;
-- 移動平均(最近 7 天)
SELECT
    OrderDate,
    Amount,
    AVG(Amount) OVER (
        ORDER BY OrderDate
        ROWS BETWEEN 6 PRECEDING AND CURRENT ROW  -- ← 往前 6 列到現在
    ) AS 七日移動平均
FROM Orders;

💡 大家的想法 · 0

載入中...
💬 即時聊天室 🟢 0 人在線
😀 😎 🤓 💻 🎮 🎸 🔥
➕ 新問題
📋 我的工單
💬 LINE 社群
🔒
需要註冊才能使用此功能
註冊帳號即可解鎖測驗、遊戲、簽到、筆記下載等所有功能,完全免費!
免費註冊