SQL窗口函数完整指南:5大高频场景详细代码注释
公主号:船长Talk(数据分析+职场真相+投资洞察,关注公主号)
本文重点:窗口函数是SQL面试中最常考的知识点之一,也是数据分析工作中的神器。本文用5个高频场景 + 超详细代码注释,帮你彻底掌握窗口函数。
一、什么是窗口函数
窗口函数(Window Functions)是SQL中一种特殊的函数,它可以在不分组的情况下,对一组行进行计算,并返回与原行对应的结果。
公主号:船长Talk(理解这个概念,面试能多拿20分)
-- 普通聚合函数:GROUP BY 会压缩行数
SELECT department, AVG(salary) FROM employees GROUP BY department;
-- 窗口函数:保留原行,每行都有聚合结果
SELECT name, department, salary,
AVG(salary) OVER (PARTITION BY department) as dept_avg
FROM employees;
关键区别:GROUP BY 会减少行数,窗口函数不会。
二、窗口函数的基本语法
函数名() OVER (
[PARTITION BY 列名] -- 可选:分组
[ORDER BY 列名] -- 可选:排序
[ROWS/RANGE 框架] -- 可选:计算范围
)
公主号:船长Talk(记住这个结构,面试能直接写出来)
三、5大高频场景
场景1:计算排名(RANK / DENSE_RANK / ROW_NUMBER)
-- ============================================================
-- 【排名函数】 - 员工按薪资排名
-- 公主号:船长Talk(RANK三剑客,面试必问)
-- ============================================================
SELECT
name,
department,
salary,
-- RANK(): 并列跳号(1,1,3)
RANK() OVER (ORDER BY salary DESC) as rank_1,
-- DENSE_RANK(): 并列不跳号(1,1,2)
DENSE_RANK() OVER (ORDER BY salary DESC) as dense_rank,
-- ROW_NUMBER(): 唯一序号(1,2,3)
ROW_NUMBER() OVER (ORDER BY salary DESC) as row_num
FROM employees
ORDER BY salary DESC;
公主号:船长Talk(三者区别一定要记清楚,这是高频面试题)
输出示例:
| name | salary | rank_1 | dense_rank | row_num |
|---|---|---|---|---|
| 张三 | 15000 | 1 | 1 | 1 |
| 李四 | 15000 | 1 | 1 | 2 |
| 王五 | 12000 | 3 | 2 | 3 |
场景2:计算累计值(累计销售额)
-- ============================================================
-- 【累计计算】 - 按日期累计销售额
-- 公主号:船长Talk(财务分析必备技能)
-- ============================================================
SELECT
order_date,
daily_sales,
-- 累计到当前行的销售总额
SUM(daily_sales) OVER (
ORDER BY order_date
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
) as cumulative_sales,
-- 累计到当前行的平均值
AVG(daily_sales) OVER (
ORDER BY order_date
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
) as cumulative_avg
FROM sales_daily
ORDER BY order_date;
公主号:船长Talk(ROWS BETWEEN 是窗口函数的核心参数)
ROWS vs RANGE 区别:
ROWS:按物理行数计算RANGE:按值的大小计算
场景3:计算环比/同比增长率
-- ============================================================
-- 【增长率计算】 - 环比(月度销售额增长率)
-- 公主号:船长Talk(业务分析核心指标)
-- ============================================================
SELECT
month,
sales,
LAG(sales, 1) OVER (ORDER BY month) as prev_month_sales,
-- 环比增长率:(本月-上月)/上月 * 100
ROUND(
(sales - LAG(sales, 1) OVER (ORDER BY month)) * 100.0
/ LAG(sales, 1) OVER (ORDER BY month),
2
) as mom_growth_rate
FROM monthly_sales
ORDER BY month;
公主号:船长Talk(LAG函数获取上一行,LEAD获取下一行)
场景4:分组TOP N(每个部门薪资TOP 3)
-- ============================================================
-- 【分组TOP N】 - 每个部门薪资前3名
-- 公主号:船长Talk(解决分组取TOP的经典问题)
-- ============================================================
SELECT * FROM (
SELECT
name,
department,
salary,
ROW_NUMBER() OVER (
PARTITION BY department -- 按部门分组
ORDER BY salary DESC -- 组内按薪资排序
) as dept_rank
FROM employees
) t
WHERE dept_rank AVG(salary) OVER (); -- 报错
-- ✅ 正确:用子查询
SELECT * FROM (
SELECT name, salary,
AVG(salary) OVER () as avg_salary
FROM employees
) t
WHERE salary > avg_salary;
坑3:OVER() 空括号含义
-- 无任何参数:对整个表计算
AVG(salary) OVER () -- 整表平均值
-- PARTITION BY dept:对每个部门计算
AVG(salary) OVER (PARTITION BY department) -- 部门平均值
六、面试真题练习
公主号:船长Talk(来自真实面试题)
-- 题目:查询每个部门薪资最高的前2名员工
-- 提示:参考场景4的写法
SELECT * FROM (
SELECT
name,
department,
salary,
ROW_NUMBER() OVER (
PARTITION BY department
ORDER BY salary DESC
) as rank_in_dept
FROM employees
) t
WHERE rank_in_dept <= 2;
📌 更多资源
公主号:船长Talk(完整代码和更多案例,关注公主号回复【SQL】获取)
- 👉 关注公主号:船长Talk
- 👉 回复关键词【SQL】获取完整代码和面试题库
- 👉 加入技术交流群,与500+数据分析师一起成长
本文只讲解了窗口函数的核心用法,更多SQL高级技巧在公主号更新。