跳转到主要内容
窗口函数可让你对与当前行相关的一组行进行计算。 它们可用于执行与聚合函数类似的计算,但不同之处在于,窗口函数不会将多行分组成单个输出,而是仍会返回各个行。

标准窗口函数

ClickHouse 支持窗口和窗口函数的标准 SQL 语法。 下表展示了当前支持的功能:
功能支持?说明
临时窗口定义 (count(*) OVER (PARTITION BY id ORDER BY time DESC))
包含窗口函数的表达式,例如 (count(*) OVER ()) / 2
WINDOW 子句 (SELECT ... FROM table WINDOW w AS (PARTITION BY id))
ROWS 窗口帧
RANGE 窗口帧未显式指定窗口帧时,默认使用它 (RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) 。
DateTime RANGE OFFSET 窗口帧的 INTERVAL 语法请改为直接指定秒数 (RANGE 适用于任何数值类型) 。
GROUPS 窗口帧
在窗口帧上计算聚合函数 (sum(value) OVER (ORDER BY time))支持所有聚合函数。
rank(), dense_rank()/denseRank(), row_number()
percent_rank()/percentRank()可高效计算某个值在分区内的相对排名。它可替代更冗长且计算开销更高的手动 SQL 写法:ifNull((rank() OVER (PARTITION BY x ORDER BY y) - 1) / nullif(count(1) OVER (PARTITION BY x) - 1, 0), 0)
cume_dist()计算某个值在一组值中的累计分布。返回值小于或等于当前行值的行所占的百分比。
lag/lead(value, offset)你也可以使用以下任一变通方法:
1) any(value) OVER (... ROWS BETWEEN <offset> PRECEDING AND <offset> PRECEDING),或者对于 lead,使用 FOLLOWING 替代 PRECEDING
2) lagInFrame/leadInFrame,它们与前者类似,但会遵循窗口帧。若要获得与 lag/lead 完全相同的行为,请使用 ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
ntile(buckets)例如,可将窗口指定为 (PARTITION BY x ORDER BY y ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)

语法

  • PARTITION BY - 定义如何将结果集划分为多个组。
  • ORDER BY - 定义在计算 aggregate_function 时,如何对组内的行进行排序。
  • ROWS or RANGE - 定义窗口帧的边界,aggregate_function 在窗口帧内进行计算。
  • WINDOW - 允许多个表达式使用同一个窗口定义。

仅可作为窗口函数使用的函数

以下函数只能作为窗口函数使用。其中大多数是标准 SQL 函数;lagInFrameleadInFramenonNegativeDerivative 是 ClickHouse 扩展。
FunctionDescription
row_number()从 1 开始对当前行在其分区内进行编号。
first_value(x)返回其有序窗口帧中计算出的第一个值。
last_value(x)返回其有序窗口帧中计算出的最后一个值。
nth_value(x, offset)返回其有序窗口帧中第 n 行 (偏移量) 对应计算结果里的第一个非 NULL 值。
rank()对当前行在其分区内进行排名,排名中会有空缺。
dense_rank()对当前行在其分区内进行排名,排名中没有空缺。
lagInFrame(x)返回其有序窗口帧中位于当前行之前指定物理偏移位置的行所计算出的值。
leadInFrame(x)返回其有序窗口帧中位于当前行之后偏移若干行的位置所计算出的值。
nonNegativeDerivative(metric_column, timestamp_column[, INTERVAL X UNITS])计算 metric_column 相对于 timestamp_column 的非负导数。这是 ClickHouse 特有的函数。

示例

下面来看一些窗口函数的使用示例。

为行编号

聚合函数

将每位球员的薪资与其所在球队的平均薪资进行比较。
比较每位球员的薪资与其所在球队的最高薪资。

按列分区

窗口帧界定

真实场景示例

以下示例用于解决常见的实际问题。

各部门的最高/总工资

累积和

移动平均 / 滑动平均 (每 3 行)

移动平均 / 滑动平均 (每 10 秒)

移动平均 / 滑动平均 (每 10 天)

温度以秒级精度存储,但使用 RangeORDER BY toDate(ts) 时,我们构造出的窗口帧大小为 10 个单位;而由于使用了 toDate(ts),这里的单位是天。

参考资料

GitHub Issues

有关窗口函数初步支持的路线图,请参见此 issue 所有与窗口函数相关的 GitHub issue 都带有 comp-window-functions 标签。

测试

这些测试包含当前已支持语法的示例: https://github.com/ClickHouse/ClickHouse/blob/master/tests/performance/window&#95;functions.xml https://github.com/ClickHouse/ClickHouse/blob/master/tests/queries/0&#95;stateless/01591&#95;window&#95;functions.sql

Postgres 文档

https://www.postgresql.org/docs/current/sql-select.html#SQL-WINDOW https://www.postgresql.org/docs/devel/sql-expressions.html#SYNTAX-WINDOW-FUNCTIONS https://www.postgresql.org/docs/devel/functions-window.html https://www.postgresql.org/docs/devel/tutorial-window.html

MySQL 文档

https://dev.mysql.com/doc/refman/8.0/en/window-function-descriptions.html https://dev.mysql.com/doc/refman/8.0/en/window-functions-usage.html https://dev.mysql.com/doc/refman/8.0/en/window-functions-frames.html
最后修改于 2026年7月1日