SQL窗口函数完整指南:5大高频场景实战

4 阅读4分钟

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(三者区别一定要记清楚,这是高频面试题)

输出示例

namesalaryrank_1dense_rankrow_num
张三15000111
李四15000112
王五12000323

场景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高级技巧在公主号更新。