窗口函数

Hubble支持在选择查询返回的行的子集上进行函数操作。即为为窗口函数,它允许您通过一次操作多个行来计算值。窗口函数操作的行子集称为窗口框架。

有关受支持的窗口函数的完整列表,请参见函数内容。所有聚合函数也可以用作窗口函数。有关更多信息,请参见下面的示例。

窗口的定义

窗口使用over 或 window 关键字定义

窗口函数机制

窗口功能通过以下方式工作:

  1. 使用选择查询创建“虚拟表”。
  2. 将该表分割为具有窗口定义的窗口框架。您可以在OVER子句中直接在窗口函数之后定义窗口框架,也可以在window子句中作为选择查询的一部分定义窗口框架。
  3. 将窗口函数应用于每个窗口框架。

例如,考虑一个查询,其中为每个窗口函数调用定义了窗口:

SELECT DISTINCT(city),
             SUM(revenue) OVER () AS total_revenue,
             SUM(revenue) OVER (PARTITION BY city) AS city_revenue
            FROM rides
        ORDER BY city_revenue DESC;

其操作可以描述如下(此处列出的编号步骤对应于下图中的编号):

  1. 外部使用 SELECT DISTINCT(city) ... FROM RIDES 创建一个用于窗口函数操作的虚拟表
  2. 窗口函数 SUM(revenue) OVER () 在包含查询输出的所有行的窗口框架上进行操作。
  3. 窗口函数 SUM(revenue) OVER (PARTITION BY city)轮流操作多个窗框;每个框架包含不同城市分区的revenue

window-functions.png

提示说明:

使用窗口函数最重要的部分是理解窗口函数将在框架中操作哪些数据。默认情况下,窗口框架包含分区的所有行。如果对分区进行排序,默认框架将包含从分区的第一行到当前行的所有行。换句话说,在创建窗口框架时添加一个ORDER BY子句(例如,PARTITION BY x ORDER by y)会产生以下效果:

  • 它使窗口框架内的行有序。

  • 它改变了函数调用的行,不再是窗口框架中的所有行,而是“第一行”和当前行之间的一个子集。

您应该了解作为窗口函数使用的任何聚合函数的行为。如果您没有看到您期望从窗口函数中看到的结果,这种行为可以解释原因。您可能需要在窗口定义中显式地指定框架边界。

  • 常见的开窗函数

    rank() over()、dense_rank() over()、row_number() over()比较

> create table score(study_no  varchar(10),class_no  int,fenshu  int);
    insert into score values('0002',1,95);
    insert into score values('0008',1,84);
    insert into score values('0001',1,86);
    insert into score values('0004',1,86);
    insert into score values('0003',2,89);
    insert into score values('0005',2,86);
    insert into score values('0006',3,92);
    insert into score values('0007',3,86);
> select *, rank() over (partition by class_no  order by fenshu desc) as ranking from score
  study_no | class_no | fenshu | ranking  
+----------+----------+--------+---------+
  0002     |        1 |     95 |       1  
  0008     |        1 |     84 |       4  
  0001     |        1 |     86 |       2  
  0004     |        1 |     86 |       2  
  0003     |        2 |     89 |       1  
  0005     |        2 |     86 |       2  
  0006     |        3 |     92 |       1  
  0007     |        3 |     86 |       2 
> select *,dense_rank() over (partition by class_no  order by fenshu desc) as dese_rank from score
  study_no | class_no | fenshu | dese_rank  
+----------+----------+--------+-----------+
  0002     |        1 |     95 |         1  
  0008     |        1 |     84 |         3  
  0001     |        1 |     86 |         2  
  0004     |        1 |     86 |         2  
  0003     |        2 |     89 |         1  
  0005     |        2 |     86 |         2  
  0006     |        3 |     92 |         1  
  0007     |        3 |     86 |         2 
> select *,row_number() over (partition by class_no  order by fenshu desc) as row_num from score;
  study_no | class_no | fenshu | row_num  
+----------+----------+--------+---------+
  0002     |        1 |     95 |       1  
  0008     |        1 |     84 |       4  
  0001     |        1 |     86 |       2  
  0004     |        1 |     86 |       3  
  0003     |        2 |     89 |       1  
  0005     |        2 |     86 |       2  
  0006     |        3 |     92 |       1  
  0007     |        3 |     86 |       2