Appearance
SQL 开窗函数入门:ROW_NUMBER、RANK、LAG 这些函数到底怎么用
开窗函数是 SQL 里非常实用的一类能力,尤其适合做:
- 排名
- 分组内排序
- 上一行 / 下一行对比
- 同组内累计分析
如果只是背函数名,通常很快就会忘。真正更好记的方式是先理解它到底解决了什么问题。
一、开窗函数解决什么问题
你可以把它理解成:
在不把结果集“聚合成一行”的前提下,对某个分组窗口里的数据做分析计算。
这点和普通聚合函数最大的区别在于:
- 普通聚合经常会把多行压成一行
- 开窗函数通常仍然保留原始行,只是在每一行上附加分析结果
二、最常见的几个函数
1. ROW_NUMBER()
作用:给每一行生成一个唯一递增序号。
适合场景:
- 组内排序后取第一条
- 做分页辅助排序
2. RANK()
作用:计算排名,遇到并列时名次会跳跃。
例如分数:
- 100 分,第 1 名
- 100 分,第 1 名
- 90 分,第 3 名
3. DENSE_RANK()
作用:计算排名,遇到并列时名次不会跳跃。
例如分数:
- 100 分,第 1 名
- 100 分,第 1 名
- 90 分,第 2 名
4. LAG()
作用:取当前行之前某一行的值。
适合场景:
- 和上一条记录比较
- 看环比、趋势变化
5. LEAD()
作用:取当前行之后某一行的值。
适合场景和 LAG() 类似,只是方向相反。
6. FIRST_VALUE() / LAST_VALUE()
作用:取窗口内的第一个值或最后一个值。
适合场景:
- 看某个分组里的首条状态
- 看一段时间里的起点和终点值
三、一个最简单的理解框架
学习开窗函数时,可以先把语句结构记成这样:
sql
函数() over (
partition by 分组字段
order by 排序字段
)其中:
partition by:决定按什么分组order by:决定窗口内的顺序
如果没有 partition by,就表示整个结果集当成一个窗口。
四、典型使用场景
场景 1:每个部门工资最高的员工
可以先按部门分组,再按工资倒序,用 ROW_NUMBER() 给每组排序,然后取每组第 1 条。
场景 2:看销量排名
可以用 RANK() 或 DENSE_RANK()。
场景 3:和上一天数据做对比
可以用 LAG() 取前一天的值,再做差值计算。
五、一个容易混淆的点
很多人刚开始会把“分组”理解成 GROUP BY。
但两者并不一样:
GROUP BY通常会改变结果集行数- 开窗函数分析后,原始明细行通常还在
所以它特别适合“既想保留明细,又想做统计分析”的场景。
一句话总结
开窗函数最有价值的地方在于:
不破坏原始明细行的前提下,对分组内的数据做排序、排名、对比和分析。
如果你经常写报表、排行、趋势分析 SQL,这类函数几乎迟早都会用到。