You need to enable JavaScript to run this app.
导航

窗口函数

最近更新时间2023.05.30 11:57:22

首次发布时间2022.12.15 10:08:27

窗口函数是指:查询的输入参数是从上一个查询结果的一行或多行的“窗口”中取出的。例如:对查询结果分组进行排名展示,对查询结果分组再次进行累加等。
窗口函数常在业务中用于同比环比分析,top n 的排序等。

使用示例

原表为:

abce
11110
11220
11330
121100
122200
21160
31180

查询 SQL 为:

select a, b, c, sum(e), sum(sum(e)) over 
    (partition by a,b order by a,b,c rows between 3 preceding and 3 following) 
    as acc_sum
from t0_local group by a,b,c order by a,b,c;

该 SQL 的返回如下:

abcsum(e)acc_sum
1111010
1122030
1133060
121100100
122200300
2116060
3118080

即通过将结果开了(1,1),(1,2),(2,1),(3,1)四个窗口,并在acc_sum列输出每个窗口内的累加值。

语法详解

可以具体参考如下文档来了解 window function 的详细语法: https://sqlite.org/windowfunctions.html
在此章节,我们会简要介绍已经当前已经实现的语法。
典型的语法示例为:

select a, b, window_founction(c) over 
    (partition by a,b order by a,b rows between n preceding and m following)
  1. 示例中的 window_founction() 指代可以被开窗的函数,包括 ClickHouse 全部的聚合函数(例如sum, avg, count, min, max等),以及 Navigation 函数,目前 Navigation 函数仅支持以下四种:rank,row_number,dense_rank,percent_rank

    1. row_number() 按照值排序时产生一个自增编号,不会重复

    2. rank() 按照值排序时产生一个自增编号,值相等时会重复,会产生空位

    3. dense_rank() 按照值排序时产生一个自增编号,值相等时会重复,不会产生空位

    4. percent_rank() 按照值排序时产生一个百分比值,值等于 (rank() - 1)/(- 1)

  2. OVER的子句包含 partition by , order byrows 三个组成部分:

    1. partition by,指对数据进行窗口的分割。和 Group By 不同,不同窗口的数据并不会像 Group by 那样合并为一行,而只是为了标识在分割后进行对哪些组别的数据进行order byrow 操作。

    2. order by,在over子句中,order by 只是用来决定窗口函数按照什么顺序进行计算,但对结果呈现的排列顺序没有影响。

    3. rows ,语义即为以 row 为单位来计算 window frame 的范围。举例如下, rows between 3 preceding and 2 following 的意思就是说以当前行为参考,frame的范围包括了往前3行和往后2行。假如当前行为 n,那么frame的范围就是 [n-3, n+2]。rows 部分可以被省略。

  3. 我们支持对窗口的命名,举例如下:

SELECT a                        AS a,
       row_number() OVER win    AS row_number,
       rank() OVER win          AS rank,
       dense_rank() OVER win    AS dense_rank,
       percent_rank() OVER win  AS percent_rank
FROM t2
WINDOW win AS (ORDER BY a);

在以上 SQL语句中,我们用 win 来代替了一个 window: OVER (ORDER BY a),此时,可以在多个输出列中使用相同的 window。

  1. Window function 中 frame 的起始和终止偏移量可以用已经输出的列来表示。举例如下:
select a, b, c, d, e, sum(e), sum(sum(e)) over 
    (partition by a,b order by a,b,c rows between d preceding and e following) 
    as acc_sum
from t0_local group by a,b,c order by a,b,c;

假如 d 和 e 都是整数类型,那么就可以用 d 和 e 的值来代表偏移量, 此偏移量是逐行使用的。

deprecedingfollowing
1212
3434
  1. 窗口函数有对特定的SQL做优化,如果 preceding 和 following 符合以下条件那么就会通过 streaming 的方式来计算结果(每行数据只会被扫描一次),可以提升读取性能。
precedingfollowingstreaming
ignoreignoretrue
Unbounded precedingCurrent rowtrue
Unbounded preceding常数,比如3, 5true
Anything elseAnything elsefalse