导读:本期聚焦于小伙伴创作的《SQL如何实现复杂的分组统计需求?窗口函数全场景解析》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《SQL如何实现复杂的分组统计需求?窗口函数全场景解析》有用,将其分享出去将是对创作者最好的鼓励。

SQL中的窗口函数能够在保留原表所有行的基础上,按照指定的规则对数据进行分组统计计算,完美适配复杂分组统计需求,避免了多次关联子查询带来的性能损耗和代码复杂度。它和普通的聚合函数不同,不会将多行数据合并成一行,而是为每一行数据返回对应的统计结果。

SQL如何实现复杂的分组统计需求?窗口函数全场景解析

窗口函数基本语法

窗口函数的标准语法结构如下,其中OVER()子句是核心,用于定义统计的窗口范围:

-- 基本语法结构
函数名([参数]) OVER (
    [PARTITION BY 分组列1, 分组列2...]
    [ORDER BY 排序列1 [ASC|DESC], 排序列2 [ASC|DESC]...]
    [窗口帧定义]
)

语法的几个核心部分说明:

  • PARTITION BY:可选,用于指定分组的列,作用类似GROUP BY,但是不会合并行,只是把相同值的行划分到同一个窗口内
  • ORDER BY:可选,用于指定窗口内数据的排序规则,很多窗口函数的计算结果依赖排序
  • 窗口帧定义:可选,用于指定窗口内的数据范围,比如从第一行到当前行,默认是分区内的所有行

常见窗口函数分类

窗口函数主要分为排名函数、聚合窗口函数、取值窗口函数三类,适配不同的统计场景:

分类常见函数功能说明
排名函数ROW_NUMBER、RANK、DENSE_RANK计算数据在分组内的排名
聚合窗口函数SUM、AVG、COUNT、MAX、MIN在窗口内完成聚合计算,返回每行对应的聚合结果
取值窗口函数LAG、LEAD、FIRST_VALUE、LAST_VALUE获取窗口内前后行或者首尾行的数据

全场景示例解析

场景1:分组排名统计

需求:统计每个部门内员工的薪资排名,相同薪资排名规则为并列排名且后续排名不跳跃。

这里使用DENSE_RANK函数,相同薪资会得到相同排名,下一个排名紧接着上一个排名,不会跳过序号:

-- 员工表结构示例:employee(id, name, dept, salary)
SELECT 
    id,
    name,
    dept,
    salary,
    -- 按部门分区,按薪资降序排名
    DENSE_RANK() OVER (PARTITION BY dept ORDER BY salary DESC) AS dept_salary_rank
FROM employee;

场景2:分组累计求和

需求:统计每个部门内员工薪资从高到低的累计薪资,方便查看薪资分布。

使用SUM作为窗口函数,配合窗口帧定义ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW,表示从分区第一行到当前行的范围做求和:

SELECT 
    id,
    name,
    dept,
    salary,
    -- 按部门分区,按薪资降序排序,累计求和到当前行
    SUM(salary) OVER (
        PARTITION BY dept 
        ORDER BY salary DESC
        ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
    ) AS cum_sum_salary
FROM employee;

场景3:组内占比统计

需求:计算每个员工的薪资占所在部门总薪资的比例。

可以用两次窗口函数,一次计算部门总薪资,一次计算当前行薪资的占比:

SELECT 
    id,
    name,
    dept,
    salary,
    -- 计算部门总薪资
    SUM(salary) OVER (PARTITION BY dept) AS dept_total_salary,
    -- 计算占比,保留两位小数
    ROUND(salary * 1.0 / SUM(salary) OVER (PARTITION BY dept), 2) AS salary_ratio
FROM employee;

场景4:移动平均计算

需求:统计每个员工前2行到后2行的平均薪资,用于平滑薪资波动分析。

通过窗口帧定义ROWS BETWEEN 2 PRECEDING AND 2 FOLLOWING指定前后各2行的范围:

SELECT 
    id,
    name,
    dept,
    salary,
    -- 计算前2行到后2行的移动平均薪资
    AVG(salary) OVER (
        PARTITION BY dept 
        ORDER BY id
        ROWS BETWEEN 2 PRECEDING AND 2 FOLLOWING
    ) AS moving_avg_salary
FROM employee;

场景5:分组内前后值取值

需求:获取每个员工的上一个入职员工的姓名,假设员工表有hire_date入职日期字段。

使用LAG函数获取当前行之前指定偏移量的数据:

SELECT 
    id,
    name,
    dept,
    hire_date,
    -- 获取同部门内上一个入职的员工姓名,没有则返回无
    LAG(name, 1, '无') OVER (PARTITION BY dept ORDER BY hire_date) AS prev_emp_name
FROM employee;

使用注意事项

  • 窗口函数只能出现在SELECT子句和ORDER BY子句中,不能用于WHERE、GROUP BY、HAVING子句
  • 如果OVER子句中没有PARTITION BY,那么整个表会作为一个大的窗口进行统计
  • 不同的数据库对窗口函数的支持略有差异,比如MySQL从8.0版本开始支持窗口函数,使用前需要确认数据库版本
  • 窗口帧定义如果不指定,默认是RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW,和ROWS模式的区别在于处理相同排序值的行时范围不同

SQL窗口函数分组统计聚合函数修改时间:2026-06-21 08:24:29

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。