SQL语法进阶篇(二),数据库复杂查询——窗口函数
在学习和实践窗口函数之前,需要准备好工具,以确保能够顺利编写、运行和调试 SQL 语句。这里我选用的是 Kooboo 的SQL数据库在线工具:
1、创建数据表
2、查询数据表
二、 窗口函数(Window Function)
1. 定义与基本原理
窗口函数是对一组行(称为窗口)执行计算,并为每一行返回一个结果。它不像传统的聚合函数那样将结果集分组为单个行,而是在不改变结果集行数的情况下,为每一行计算一个聚合值。窗口函数通过OVER
子句来定义窗口的范围和排序规则。
2. 常见窗口函数类型及用途
核心关键字:
-
PARTITION BY
:定义分组窗口。 -
ORDER BY
:窗口内排序。 -
ROWS/RANGE
:定义窗口范围。
- 聚合窗口函数
- 概念:包括
SUM()
、AVG()
、MIN()
、MAX()
等传统聚合函数作为窗口函数使用。 - 使用场景:用于计算累计值、移动平均值等。例如,计算每个月的累计销售额,或者计算最近几个月的移动平均销售额。
- 示例:假设有
sales
表,包含month
和sales_amount
字段,要计算每个月的累计销售额,可使用以下查询:SELECT month,sales_amount,SUM(sales_amount) OVER (ORDER BY month) AS cumulative_sales FROM sales;-- OVER (ORDER BY month) 表示按照 month 列进行排序,窗口的范围是从结果集的第一行到当前行 -- AS cumulative_sales:这是为计算结果指定的别名,方便在结果集中引用
- 概念:包括
- 排名窗口函数
- 概念:包括
RANK()
、DENSE_RANK()
、ROW_NUMBER()
等,用于为结果集中的行分配排名。 - 使用场景:对数据进行排名,例如对员工的工资进行排名,找出工资最高的前几名员工。
- 示例:
SELECT month,sales_amount,RANK() OVER (ORDER BY sales_amount DESC) AS sales_rank FROM sales;-- RANK()函数会根据销售额降序排列为每一行分配排名 -- 如果有相同的销售额,会出现并列排名,且下一个排名会跳过相应的序号
- 概念:包括
- 分析窗口函数
- 概念:如
LAG()
、LEAD()
、FIRST_VALUE()
、LAST_VALUE()
等,用于获取当前行前后的数据或窗口内的第一个、最后一个值。 - 使用场景:分析数据的变化趋势,例如比较相邻月份的销售额变化。
- 示例:
SELECT month,sales_amount,LAG(sales_amount) OVER (ORDER BY month) AS prev_month_sales FROM sales;-- LAG(sales_amount) OVER (ORDER BY month)会返回当前行上一行的销售额,方便比较相邻月份的销售情况。
- 概念:如
3. 窗口范围(Frame)的本质
窗口函数在ORDER BY
排序后,通过 ** 窗口范围(Frame)** 定义参与计算的行集合。它决定了 “当前行” 的上下边界,使得聚合函数(如SUM
、AVG
)或排名函数(如RANK
)能在特定范围内计算。
核心作用:精确控制窗口函数的计算范围,实现累计值、滑动平均、移动统计等复杂分析。
-
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
:从第一行到当前行。 -
RANGE BETWEEN INTERVAL '7' DAY PRECEDING AND CURRENT ROW
:按时间范围(如7天滑动窗口)。
4. 默认窗口范围:隐式的ROWS模式
若未显式声明ROWS
或RANGE
,窗口函数默认使用:
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
即从排序后的第一行到当前行,形成一个累计窗口。
示例(等价写法):
-- 隐式默认写法
SUM(sales_amount) OVER (ORDER BY month) -- 显式声明写法
SUM(sales_amount) OVER (ORDER BY month ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)