SQL窗口函数详解

2,042 阅读3分钟

最近看完《SQL基础教程》,感觉其中的窗口函数部分讲得不太清楚,同时发现网上的许多教程也存在类似的问题,主要体现在指定窗口框架(即ROWS|RANGE BETWEEN)部分讲解得不够清楚和深入,所以在这里凭借我的个人理解把窗口函数相关内容梳理一遍,欢迎指正!

1 概述

窗口函数是只能用于SELECT子句中的,可以返回基于分组的、与指定的相邻若干行相关的统计值的函数。

  • 基本组成:

    [函数名] OVER ([分组 PARTITION BY] 
                  [排列顺序 ORDER BY] 
                  [窗口框架])
    
  • 执行顺序:分组-->按顺序排列-->对每个窗口执行函数

例如:

SELECT product_id, product_name, product_type, sale_price,
    	SUM(sale_price) OVER (PARTITION BY product_type
                            	ORDER BY product_id DESC
                            	ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) sum
FROM Product;

|400

这个窗口函数按顺序执行了以下操作:

  • PARTITION BY product_type:按product_type分组
  • ORDER BY product_id DESC:每组内按product_id降序排列
  • ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING:指定当前行及相邻两行作为窗口
  • SUM(sale_price):在每个窗口内执行对sale_price的求和

2 分组:PARTITION BY

选择一个变量作为分组条件,之后的所有操作,包括排序、窗口划分、函数执行都在每个组内进行,组间互不干扰。

3 排序:ORDER BY

在某一组内,按指定变量排序,以便划分窗口。

4 (重点!)窗口框架:

指定哪些行参与当前行统计值的计算。

语法:

RANGE|ROWS BETWEEN 上限 AND 下限
  • 上下限:

    [CURRENT ROW] | [<num>|UNBOUNDED PRECEDING|FOLLOWING]
    
    • 当前行:CURRENT ROW

    • 上下滑动:

      • PRECEDING为当前行向上滑动,FOLLOWING为当前行向下滑动。
      • 可以使用<num>指定向上/下滑动的单位数(ROWRANGE单位含义不同),如2 PRECEDING代表包括本行、本行之上一单位与本行之上两单位;或者使用UNBOUNDED,代表选中当前行之上/下的所有。
    • 若想表示当前行及其上方若干单位,可省略BETWEEN AND,简写为

      ROWS|RANGE <num>|UNBOUNDED PRECEDING
      
  • ROWSRANGE

    • ROWS代表每一行在表中的绝对位置,滑动的每一单位为一行,可以脱离ORDER BY使用。
    • RANGE必须搭配ORDER BY使用,表示ORDER BY指定变量的值。滑动的单位为值变化1,上下限代表值的区间,如1 PRECEDING代表当前行的值向上变动1单位。注意是向”上“变动1单位而不是”加“或”减“1单位,因为这与ORDER BY的升降序有关。升序时为减,降序时为加,但不变的是都是朝表的上方向。

    例如:

    SELECT s_id, s_score,
    		SUM(s_score) OVER (ORDER BY s_score 
                                       ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) row_,
    		SUM(s_score) OVER (ORDER BY s_score 
                                       RANGE BETWEEN 9 PRECEDING AND CURRENT ROW) range_9,    
    		SUM(s_score) OVER (ORDER BY s_score 
                                       RANGE BETWEEN 10 PRECEDING AND CURRENT ROW) range_10
    FROM Student;          
    

    |250

  • 默认值

    • ORDER BY与窗口都缺失时,默认为
      ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
      
    • 指定ORDER BY,缺失窗口时,默认为
      RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
      

若触及边界,则将边界外的行省去,如第一个例子中的绿色部分。

5 函数

  • 专用窗口函数
    • RANK:排名,同名次的行算多个
    • DENSE_RANK:排名,排名同名次的行算一个
    • ROW_NUMBER:按顺序编号
    例如:
    SELECT s_id, s_score,
           RANK() OVER (ORDER BY s_score) rank_ ,
           DENSE_RANK() OVER (ORDER BY s_score) dense_rank_  ,
           ROW_NUMBER() OVER (ORDER BY s_score) row_num_
    FROM Student;
    
    |300
  • 聚合函数
    • COUNT()
    • SUM()
    • AVG()
    • MIN()/MAX()