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 方言的文档。