「这是我参与11月更文挑战的第 20 天,活动详情查看:2021最后一次更文挑战」
窗口函数 一直是ClickHouse中很重要的功能需求。由于 Alexander Kuzmenkov 的出色工作,ClickHouse现在有了实验性的支持,用户可以开始尝试它们了。之前我对功能进行了广泛的测试,以找出目前哪些功能可以使用,哪些不能使用,哪些不被支持。
本篇我们使用需求来描述需要测试的功能,帮助我们理解和管理每个功能的测试过程。在这篇文章中,我们将全面了解窗口功能,包括向还未用过此功能的用户,从以下几个方面:详细的语法,以及对当前限制的总结。
在这篇文章中,我们使用了最新的稳定的ClickHouse版本:21.5.5.12
什么是窗口?
窗口函数允许用户使用窗口内的当前行存在的某种关系对表中数据行进行计算(感觉有点绕口)。
因此,使用窗口函数时,你必须始终牢记当前行,也就是你正在操作的数据。使用窗口函数的一个简单例子是计算动态数据的平均值。例如,我们可以通过使用 ROWS
和对其应用avg聚合函数,轻松地计算出一个序列中最后四个值的动态平均数。
SELECT
number,
avg(number) OVER (ROWS BETWEEN 3 PRECEDING AND CURRENT ROW) AS mv4
FROM values('number Int8', 1, 2, 3, 4, 5, 6, 7, 8)
/* answer */
┌─number─┬─mv4─┐
│ 1 │ 1 │
│ 2 │ 1.5 │
│ 3 │ 2 │
│ 4 │ 2.5 │
│ 5 │ 3.5 │
│ 6 │ 4.5 │
│ 7 │ 5.5 │
│ 8 │ 6.5 │
└────────┴─────┘
注意,数字4之前的输出是无效的,因为没有足够的数据。
除了当前行之外,还有一个适用于 RANGE
的当前行的同级别的概念。如果指定了ORDER BY子句,当前行的同级是落入同一排序桶的行。
SELECT
number,
sum(number) OVER (ORDER BY number ASC RANGE BETWEEN CURRENT ROW AND CURRENT ROW)
FROM numbers(1, 3)
/* answer */
┌─number─┬─sum(number) OVER (ORDER BY number ASC RANGE BETWEEN CURRENT ROW AND CURRENT ROW)─┐
│ 1 │ 1 │
│ 2 │ 2 │
│ 3 │ 3 │
└────────┴──────────────────────────────────────────────────────────────────────────────────┘
我们在上面看到的是,每个结果行都有一个窗口函数被评估。因为我们没有使用 PARTITION BY
子句,这意味着我们只有一个窗口。
现在,因为我们有一个 RANGE
子句,这意味着对于每一行,窗口函数为该行评估了一个相应的窗口。该窗口总是与窗口内的当前行一起滑动。窗口被指定为 BETWEEN CURRENT ROW AND CURRENT ROW
,这意味着每个窗口只包括当前行。
因为我们有一个ORDER BY子句,将每个值分配到它自己的排序桶中,那么我们就有了当前行与当前行同行的情况。因此,每一个窗口只包括当前行的值,这个值被传递给sum函数,而sum函数又返回每一个窗口的当前行的值。