說明
frame子句是用來定義窗口的子集。
也許看到上面的說明依舊讓人很困惑,所以讓我們實際舉個例子看看吧!
範例:將訂單按照 member 分組,按照 order_id 順序,累計總和到目前為止的 amount。
看看上面的例子,我們的第一個窗口是
PARTITION BY member ORDER BY order_id
隨後還有 frame子句形成窗口的子集
ROWS UNBOUNDED PRECEDING
,此語句表示當前行往上的所有行,也就是說當執行到 order_id = 3 時,產生的窗口子集如下:上述範例中我們可以看到 frame 子句的作用就是把
PARTITION BY
出來的窗口再分割一次,所以定義上才會說是窗口的子集。結構
frame_units
frame 計算的單位分為
ROWS
和 RANGE
,其中 RANGE
又會依據前面的 ORDER BY
子句而有所差異- ROWS:以行為單位。
- RANGE With ORDER BY:當
ORDER BY
的目標等值時,視為同一個RANGE
。
- RANGE Without ORDER BY:同一個
PARTITION
內的資料都視為同一個RANGE
。
範例:
查看如上範例,其中
UNBOUNDED PRECEDING
表示此加總要從同一個 PARTITION 的第一行開始加總到當前 ROWS 或 RANGE,結果如下:- ROWS:以 order_id = 1 為例,就是由 5 + 10 得出 15 。
- RANGE With ORDER BY:以 order_id = 1 為例,因為是用 ORDER BY amount 加上 order_id = 9 和 order_id = 1 的 amount 皆為 10 視為同一個 RANGE,因此是 5 + 10 + 10 = 25。
- RANGE Without ORDER BY:以 order_id = 1 為例,因為沒有 ORDER BY,所以就是整個 member = A 都是同一個 RANGE,因此是 5 + 10 +10 +20 = 45。
frame_extent
用來定義 frame 的範圍。 若只指定 frame_start,則默認的 frame_end 會是
CURRENT ROW
。- CURRENT ROW:當前所在的 ROW 或 RANGE。
- UNBOUNDED PRECEDING:同一個 PARTITION 的第一行。
- UNBOUNDED FOLLOWING:同一個 PARTITION 的最後一行。
- expr PRECEDING:對於 ROWS 表示當前所在的 ROW 往前 expr 行。對於 RANGE 表示值符合當前所在的 RANGE 值 - expr 的行,若該 RANGE 為 NULL 則就是表示為同為 NULL 的行。
- expr FOLLOWING:對於 ROWS 表示當前所在的 ROW 往後 expr 行。對於 RANGE 表示值符合當前所在的 RANGE 值 + expr 的行,若該 RANGE 為 NULL 則就是表示為同為 NULL 的行。

expr PRECEDING 和 expr FOLLOWING 更多細節
- 關於 expr 的格式:
- ?:parameter marker ,也就是 prepare statement 中的
?
佔位符。 - 非負的數值
- INTERVAL 表達式: 即使用在 DATE_ADD 函數中的表達式,但時間間隔在此不可為負數。
注意當 frame_units 是 RANGE 並且 expr 是數值或 INTERVAL表達式,則必須要有 ORDER BY 子句,否則會產生以下錯誤:
- PRECEDING 和 FOLLOWING 在 frame_units 是 ROWS 時意思非常明顯是往前往後 N 行,當 frame_units 是 RANGE 時則有些模糊,因此補充以下範例以供參考:
- 以 order_id = 2 為例,當前 RANGE 為 amount = 20,其中
5 PRECEDING
表示必須將 amount 值為 20 ~ 15(20-5) 的行也納入計算,因此 range_sum 就會是 20。 - 以 order_id = 9 為例,當前 RANGE 為 amount = 10,其中
5 PRECEDING
表示必須將 amount 值為 10 ~ 5(10-5) 的行也納入計算,因此 range_sum 就會是 10 + 10 + 5。
預設值
當未指定 frame 子句時,會根據 windows spec 是否包含 ORDER BY 而有不同的預設 frame 子句-
- With ORDER BY 預設值:
- Without ORDER BY 預設值:
限制
不是所有的函數都受到 frame 子句影響,以下列出受 frame 子句影響的函數:
- 所有的 Aggregate Function (聚合函數)
- 窗口函數 - FIRST_VALUE()
- 窗口函數 - LAST_VALUE()
- 窗口函數 - NTH_VALUE()
至於其他窗口函數在 SQL 標準下是不允許使用 frame 子句的,但 MySQL 允許出現並自動將 frame 子句忽略。