题解 | 查询用户刷题日期和下一次刷题日期(窗口函数基础)
查询用户刷题日期和下一次刷题日期
https://www.nowcoder.com/practice/fed7ebf4254240fdb6a2c963996ee8ff
select user_id, date, lead(date,1) over(
partition by user_id order by date) nextdate
from questions_pass_record
order by user_id, date
窗口函数(Window Function)是 SQL 中用于在一组与当前行相关的行上执行计算的强大工具,它不会像聚合函数那样将多行合并为一行,而是保留每行的独立结果,同时附加基于 “窗口”(即指定范围的行)的计算结果。
一、窗口函数的基本语法
sql
窗口函数名(列名) OVER (
[PARTITION BY 列名1, 列名2...] -- 分区(可选):将数据按列分组,每组独立计算
[ORDER BY 列名 [ASC|DESC]] -- 排序(可选):定义窗口内的行顺序
[ROWS|RANGE BETWEEN 边界1 AND 边界2] -- 窗口范围(可选):指定窗口包含的行范围
)
- 核心作用:在不聚合行的前提下,实现 “分组内排序”“组内排名”“累计计算” 等需求。
- 与聚合函数的区别:聚合函数(如
SUM)会将分组后的多行合并为一行,而窗口函数会为每行返回一个结果,同时保留原始行的所有信息。
二、常用知识点
- 分区(PARTITION BY)类似 GROUP BY,但不合并行,而是将数据划分为多个 “窗口”(组),每个窗口独立计算。若不指定 PARTITION BY,则整个表视为一个窗口。
- 排序(ORDER BY)定义窗口内的行顺序,是排名类、累计类函数的基础(如 RANK、SUM() OVER (ORDER BY ...))。
- 窗口范围(ROWS/RANGE)用于精确指定窗口包含哪些行(默认范围因函数而异):
- ROWS:按物理行数定义范围(如 ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING 表示当前行 + 前 1 行 + 后 1 行)。
- RANGE:按逻辑值范围定义(如 RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW 表示从窗口第一行到当前行)。
- 常见简写:
- CURRENT ROW:当前行
- UNBOUNDED PRECEDING:窗口第一行
- UNBOUNDED FOLLOWING:窗口最后一行
三、常用窗口函数分类
1. 排名函数(用于分组内排序)
- RANK():分组内排名,存在并列时跳过后续名次(如 1,1,3)。
- DENSE_RANK():分组内排名,存在并列时不跳过后续名次(如 1,1,2)。
- ROW_NUMBER():分组内按顺序生成唯一序号(无并列,即使值相同也按顺序编号 1,2,3)。
2. 聚合类窗口函数(用于累计 / 分组内统计)
将常见聚合函数(SUM、AVG、MAX、MIN 等)作为窗口函数,计算窗口内的聚合结果。
- SUM():累计求和
- AVG():滑动平均值(如近 3 天平均销售额)
- MAX()/MIN():分组内最大 / 最小值
3. 偏移函数(用于获取相邻行数据)
- LAG(列名, n):获取当前行的前 n 行数据(默认 n=1)。
- LEAD(列名, n):获取当前行的后 n 行数据。
4. 其他常用函数
- FIRST_VALUE(列名):获取窗口内的第一行数据。
- LAST_VALUE(列名):获取窗口内的最后一行数据(注意默认窗口范围可能需要显式指定)。

查看20道真题和解析