「Clickhouse 窗口函数」RANGE

655 阅读2分钟

「这是我参与11月更文挑战的第 20 天,活动详情查看:2021最后一次更文挑战


如果没有指定ORDER BY子句,那么窗口分区中的所有行都被认为是当前行的对等行,下面的查询说明了这一点:

SELECT
    number,
    sum(number) OVER (RANGE BETWEEN CURRENT ROW AND CURRENT ROW)
FROM numbers(1, 3)

/* answer */
┌─number─┬─sum(number) OVER (RANGE BETWEEN CURRENT ROW AND CURRENT ROW)─┐
│      16 │
│      26 │
│      36 │
└────────┴──────────────────────────────────────────────────────────────┘

我们可以看到的是,现在窗口函数对每一行都返回相同的结果。为什么呢?

很简单:我们没有任何ORDER BY子句,结果中的所有行都被认为是当前行的同行。虽然frame仍然在窗口内滑动,每条当前行的frame总是包含所有的行。

image.png

一般来说,一个窗口既可以包括结果集中的所有行,也可以使用 PARTITION BY 子句将结果集划分为独立的窗口。所以,当没有指定PARTITION BY子句时,所有的行都会落入一个大的分区,也被称为窗口。每个窗口中的行可以使用ORDER BY子句进行排序。

当你试图理解这个功能时,窗口的比喻就很方便了。就像下面的概念图所示,在心中创建一个窗口的模拟图像,让你看到结果集中的所有行,或者只是其中的一些块。

image.png

不过上述的表达有几个需要单独拿出来说一下(不然确实有点蒙):

  1. 停下来看看 frame 到底代表什么?在前面我们使用过:ROWS以及RANGE

image.png 从英文表达上来看,说白了:

  • ROWS:针对的是行间隔,也就是frame中跨越的行数
  • RANGE:针对的是行所对应的值,RANGE 1 PRECEDING 是和当前行的值相差1形成一个frame
  1. 而在前面 Peers

image.png

可以理解为:和 current ROW 分在一个桶(也可以理解为分组)。只适用于 Range frame