窗口函数详解
一、什么是窗口函数
窗口函数(Window Function),也称为分析函数(Analytic Function),是 SQL 中用于在结果集的 “窗口”(也就是分区)内进行计算的函数。与普通聚合函数不同,窗口函数不会将多行数据聚合为一行,而是针对每一行数据,在指定的窗口范围内进行计算,并返回一个结果值,该结果值与当前行相关联,常用于数据分析、报表生成等场景。
二、窗口函数语法
窗口函数的基本语法结构如下:
<窗口函数> OVER (PARTITION BY <列名> ORDER BY <列名> [ROWS/RANGE BETWEEN <起始位置> AND <结束位置>])
<窗口函数>:常见的窗口函数包括排名函数(RANK()、DENSE_RANK()、ROW_NUMBER())、聚合窗口函数(SUM()、AVG()、COUNT()等)、偏移函数(LEAD()、LAG())等。
PARTITION BY:用于定义窗口的分区,即将结果集按照指定列进行分组,窗口函数将在每个分区内独立计算。如果不指定PARTITION BY,则整个结果集作为一个窗口。
ORDER BY:用于定义窗口内数据的排序顺序,窗口函数的计算将基于此排序进行。
ROWS/RANGE BETWEEN <起始位置> AND <结束位置>:可选参数,用于定义窗口的范围。ROWS按物理行计数,RANGE按逻辑范围计算,默认情况下,窗口范围是从分区的第一行到当前行。
三、常见窗口函数及示例
(一)排名函数
ROW_NUMBER()
功能:为结果集中的每一行生成一个唯一的连续序号,序号从 1 开始,按照ORDER BY指定的顺序依次分配。
示例:假设有一个students表,包含student_id、student_name、score字段,查询学生成绩排名:
SELECT student_id, student_name, score,
ROW_NUMBER() OVER (ORDER BY score DESC) AS ranking
FROM students;
RANK()
功能:为结果集中的每一行生成一个排名,相同的值具有相同的排名,排名会出现间断(例如,两个第一名后,下一个是第三名)。
示例:
SELECT student_id, student_name, score,
RANK() OVER (ORDER BY score DESC) AS ranking
FROM students;
DENSE_RANK()
功能:为结果集中的每一行生成一个排名,相同的值具有相同的排名,排名不会出现间断(例如,两个第一名后,下一个是第二名)。
示例:
SELECT student_id, student_name, score,
DENSE_RANK() OVER (ORDER BY score DESC) AS ranking
FROM students;
(二)聚合窗口函数
SUM()
功能:在窗口范围内计算指定列的总和。
示例:假设有一个sales表,包含sale_id、product_name、sale_date、amount字段,计算每个产品每天的累计销售金额:
SELECT sale_id, product_name, sale_date, amount,
SUM(amount) OVER (PARTITION BY product_name ORDER BY sale_date) AS cumulative_amount
FROM sales;
AVG()
功能:在窗口范围内计算指定列的平均值。
示例:计算每个产品每天的平均销售金额:
SELECT sale_id, product_name, sale_date, amount,
AVG(amount) OVER (PARTITION BY product_name ORDER BY sale_date) AS average_amount
FROM sales;
(三)偏移函数
LEAD()
功能:用于访问当前行之后的第n行的数据,常用于比较相邻行之间的值。
示例:查询每个产品当前日期的销售金额以及下一个日期的销售金额:
SELECT product_name, sale_date, amount,
LEAD(amount, 1) OVER (PARTITION BY product_name ORDER BY sale_date) AS next_amount
FROM sales;
LAG()
功能:与LEAD()相反,用于访问当前行之前的第n行的数据。
示例:查询每个产品当前日期的销售金额以及上一个日期的销售金额:
SELECT product_name, sale_date, amount,
LAG(amount, 1) OVER (PARTITION BY product_name ORDER BY sale_date) AS previous_amount
FROM sales;
四、窗口函数的应用场景
(一)数据分析与报表生成
在统计报表中,窗口函数可以方便地计算累计值、移动平均值等。例如,计算每月的累计销售额、每季度的移动平均利润等,帮助企业分析业务趋势。
(二)数据排名与筛选
通过排名函数,可以快速对数据进行排名,筛选出排名靠前或靠后的记录。比如,找出销售额排名前 10 的产品、成绩排名前 5% 的学生等。
(三)数据对比与差异分析
偏移函数LEAD()和LAG()可以用于比较相邻行的数据,分析数据的变化趋势和差异。例如,比较相邻日期的网站访问量,找出访问量波动较大的时间段。
五、注意事项
窗口函数只能出现在SELECT子句和ORDER BY子句中,不能直接用于WHERE、GROUP BY、HAVING子句。如果需要在这些子句中使用窗口函数的结果,通常需要通过子查询或 CTE(通用表表达式)来实现。
不同数据库对窗口函数的支持和语法细节可能略有差异,在实际使用时,需要参考对应数据库的官方文档。例如,Oracle、SQL Server、MySQL 8.0+ 等都支持窗口函数,但在函数名称、参数设置等方面可能存在一些不同。
通过以上对窗口函数的介绍,相信你已经对其有了较为全面的了解。合理运用窗口函数,可以让你的 SQL 查询更加高效、灵活,满足各种复杂的数据分析需求。
以上从多维度介绍了窗口函数。若你对某些函数示例、应用场景还想深入了解,或者有其他修改方向,欢迎随时告诉我。