【SQL】窗口函数

窗口函数是 SQL 中的一个高级功能,它可以在不对表的结果集进行分组的情况下,对查询结果中的每一行执行分析操作。窗口函数的作用范围是“窗口”(一组有逻辑意义的行)。通过窗口函数,可以实现排名、累计求和、移动平均等复杂的数据分析功能。


一、窗口函数的基本语法

窗口函数的标准结构如下:

<窗口函数> OVER ( PARTITION BY  <用于分组的列名>
                    ORDER BY <按序叠加的列名> 
                    ROWS|RANGE <窗口滑动的数据范围> )
  • 窗口函数:用于对数据进行操作(如排名、累计求和等),常见的函数包括 RANK()、ROW_NUMBER()、SUM()、AVG() 等。

  • OVER:窗口函数的关键字,表示窗口函数的计算范围。

  • PARTITION BY:按照某些列对数据进行分组。它类似于 GROUP BY,但不会将数据聚合成一行,而是为每组创建独立的分析窗口。

  • ORDER BY:定义数据的排序方式,通常是窗口范围内的数据需要按某列排序。

  • RANGE|ROWS: 用来限定<窗口函数>所运用的数据的范围,具体有如下这些:

    关键字解释
    UNBOUNDED PRECEDING从当前窗口的开头到当前行
    UNBOUNDED FOLLOWING从当前行到窗口的末尾
    CURRENT ROW当前行
    PRECEDING当前行往前的第 n 行(包含当前行)
    FOLLOWING当前行往后的第 n 行(包含当前行)

    示例
    取当前行和前五行:ROWS between 5 preceding and current row --共6行
    取当前行和后五行:ROWS between current row and 5 following --共6行
    取前五行和后五行:ROWS between 5 preceding and 5 following --共11行
    取当前行和前六行:ROWS 6 preceding(等价于between…and current row) --共7行
    这一天和前面6天:RANGE between interval 6 day preceding and current row --共7天
    这一天和前面6天:RANGE interval 6 day preceding(等价于between…and current row) --共7天
    字段值落在当前值-100到+200的区间:RANGE between 100 preceding and 200 following --共301个数值


二、窗口函数的特点

窗口函数与聚合函数的区别

  • 聚合函数(如 SUM()、AVG())通常是对整个表或某一分组的行进行计算,然后将结果汇总到单行。
  • 窗口函数保留了每一行的原始数据,但在此基础上对每一行计算出额外的分析数据,窗口函数不会“折叠”表中的行。

三、常见的窗口函数类型及用途

1. 排名相关函数

窗口函数的一大应用场景是排名操作。

函数作用
ROW_NUMBER()按顺序为每行分配一个唯一的编号
RANK()按排序顺序为每行分配排名,存在并列时跳号
DENSE_RANK()分配排名,存在并列时不跳号
NTILE(n)将行分成 n 个大致相等的部分,并分配组号

实例:
假如有一张名为 sales 的表,包含以下几列:

iddepartmentsales_amount
1A500
2A300
3B800
4B600
5A700

使用 ROW_NUMBER()按照部门和销售额排序:

SELECT 
    id,
    department,
    sales_amount,
    ROW_NUMBER() OVER (PARTITION BY department ORDER BY sales_amount DESC) AS rank
FROM sales;

结果:

iddepartmentsales_amountrank
5A7001
1A5002
2A3003
3B8001
4B6002

2. 累积计算函数

窗口函数也可以用于计算累计总和、平均值等。

函数作用
SUM()累加总和
AVG()累计平均值
COUNT()累计计数
MIN() / MAX()当前窗口的最小/最大值

实例:
还是用前面的sales表,想按照部门计算销售额的累计求和:

SELECT 
    department,
    sales_amount,
    SUM(sales_amount) OVER (PARTITION BY department ORDER BY sales_amount DESC) AS cumulative_sales
FROM sales;

结果

departmentsales_amountcumulative_sales
A700700
A5001200
A3001500
B800800
B6001400

3. 滑动窗口函数

在一些分析场景中,希望计算某行周围的特定范围(如前 2 行、后 2 行)的数据,这时滑动窗口函数就派上用场了。

窗口范围关键字:
ROWS:基于绝对行号。
RANGE:基于逻辑值范围。

实例:
计算每一行的当前值和前两行的销售总和:

SELECT 
    id,
    department,
    sales_amount,
    SUM(sales_amount) OVER (
        PARTITION BY department 
        ORDER BY sales_amount 
        ROWS BETWEEN 2 PRECEDING AND CURRENT ROW
    ) AS sliding_sum
FROM sales;

4. 比例分析函数

窗口函数也可以用于计算某行占某组总量的比例,如销售额占比。

实例:
计算每个部门中,每行销售额占整个部门销售额的百分比:

SELECT 
    department,
    sales_amount,
    ROUND(
        sales_amount * 1.0 / SUM(sales_amount) OVER (PARTITION BY department) * 100, 2
    ) AS percentage
FROM sales;

结果:

departmentsales_amountpercentage
A70046.67
A50033.33
A30020.00
B80057.14
B60042.86

四、窗口函数使用的注意事项

PARTITION BYORDER BY 都是可选的。

如果没有 PARTITION BY,则整个数据集视为一个组。
如果没有 ORDER BY,则窗口函数不会进行任何排序。
窗口范围(ROWS/RANGE)的使用需要搭配 ORDER BY

性能问题:
窗口函数的计算会对性能有一定影响,尤其是当 PARTITION BY 和 ORDER BY 的组合过于复杂时。尽量先将基础查询的结果保存为临时表,再针对结果应用窗口函数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值