4.3.6. 窗口函数
窗口函数也是带有 over 子句的函数,例如
select
item.order.dateTime,
sum(item.quantity)
over (order by item.order.dateTime)
as runningTotal
from Item item
此查询返回随时间推移的销售运行总计。换句话说,sum() 计算结果集当前行的窗口和所有以前的行。
窗口函数应用程序可以根据需要指定以下任何子句
可选子句
关键字
用途
结果集的分区
按分区
与 按组 非常相似,但不会将每个分区折叠成一行
分区的顺序
order by
指定分区内行的顺序
计算窗口
range,rows 或 groups
在分区内定义窗口框架的边界
限制
filter
作为聚合函数,窗口函数可以根据需要指定过滤器
例如,我们可以按账本对 running total 进行分区
select
item.book.isbn,
item.order.dateTime,
sum(item.quantity)
over (partition by item.book
order by item.order.dateTime)
as runningTotal
from Item item
每个分区独立运行,换句话说,行无法跨分区泄漏。
窗口函数应用程序的完整语法极其复杂,这一点通过此 BNF 得以体现
overClause
: "OVER" "(" partitionClause? orderByClause? frameClause? ")"
partitionClause
: "PARTITION" "BY" expression ("," expression)*
frameClause
: ("RANGE"|"ROWS"|"GROUPS") frameStart frameExclusion?
| ("RANGE"|"ROWS"|"GROUPS") "BETWEEN" frameStart "AND" frameEnd frameExclusion?
frameStart
: "CURRENT" "ROW"
| "UNBOUNDED" "PRECEDING"
| expression "PRECEDING"
| expression "FOLLOWING"
frameEnd
: "CURRENT" "ROW"
| "UNBOUNDED" "FOLLOWING"
| expression "PRECEDING"
| expression "FOLLOWING"
frameExclusion
: "EXCLUDE" "CURRENT" "ROW"
| "EXCLUDE" "GROUP"
| "EXCLUDE" "TIES"
| "EXCLUDE" "NO" "OTHERS"
窗口函数与聚合函数类似,因为它们基于包含多行的“框架”计算一些值。但与聚合函数不同,窗口函数不会展平窗口框架内的行。
窗口框架
窗口框架是给定分区内传递给窗口函数的行集合。结果集的每行都有一个不同的窗口框架。在我们的示例中,窗口框架包含分区内所有前行,即所有 item.book 相同且 item.order.dateTime 较早的行。
窗口框架的边界通过计算窗口子句控制,该子句可以指定以下模式之一
模式
定义
示例
解释
rows
由给定行数定义的框架边界
5 preceding
分区中的前 5 行
groups
由给定同级组数定义的框架边界,如果同级组通过 order by 分配了相同位置,则该组的行属于同一同级组
5 preceding
分区中前 5 个同级组中的行
range
由 order by 中用于表达式value的最大差异定义的框架边界
range between 1.0 preceding and 1.0 following
其 order by 表达式与当前行相差的最大绝对值为 1.0 的行
框架排除子句允许排除当前行周围的行
选项
解释
exclude current row
排除当前行
exclude group
排除当前行的同级组行
exclude ties
不包含当前行的对等组中的行,除了当前行
不排除其他任何行
默认值,不会排除任何内容
在默认情况下,窗口框架定义为在无界的前置行与当前行之间排除其他任何行,这意味着包括当前行在内的每行。
模式range和groups,连同框架排除模式,并非在所有数据库上都可用。
广泛支持的窗口函数
以下窗口函数在所有主流平台上都可用
窗口函数
用途
签名
row_number()
当前行与其框架内的位置
row_number()
lead()
框架中后续行的值
lead(x), lead(x, i, x)
lag()
框架中先前行的值
lag(x), lag(x, i, x)
first_value()
框架中第一行的值
first_value(x)
last_value()
框架中最后一行值
last_value(x)
nth_value()
框架中第 `n` 行的值
nth_value(x, n)
原则上,也可能将每个聚合函数或有序集合聚合函数用作窗口函数,仅需通过指定over,但并非每个函数都支持所有数据库。
窗口函数和有序集合聚合函数并非在所有数据库上都可用。即使在可用的情况下,特定功能的支持在数据库之间也存在很大差异。因此,我们不会在这里浪费时间深入展开讨论。有关这些函数的语法和语义的更多信息,请查阅您所用 SQL 方言的文档。