說明

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 計算的單位分為 ROWSRANGE ,其中 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 的行。
notion image

expr PRECEDING 和 expr FOLLOWING 更多細節

  • 關於 expr 的格式:
      1. ?:parameter marker ,也就是 prepare statement 中的 ? 佔位符。
      1. 非負的數值
      1. INTERVAL 表達式: 即使用在 DATE_ADD 函數中的表達式,但時間間隔在此不可為負數。
      注意當 frame_units 是 RANGE 並且 expr 是數值INTERVAL表達式,則必須要有 ORDER BY 子句,否則會產生以下錯誤:
  • PRECEDING 和 FOLLOWING 在 frame_units 是 ROWS 時意思非常明顯是往前往後 N 行,當 frame_units 是 RANGE 時則有些模糊,因此補充以下範例以供參考:
      1. order_id = 2 為例,當前 RANGE 為 amount = 20,其中 5 PRECEDING 表示必須將 amount 值為 20 ~ 15(20-5) 的行也納入計算,因此 range_sum 就會是 20。
      1. 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 子句忽略。

      參考