窗口函数进阶:排名、累计、移动平均一网打尽

简介: 本篇干货分享SQL窗口函数实战:一行代码轻松搞定分组取前三、累计占比、移动平均、同比环比等高频需求,告别冗长易错的子查询。涵盖ROW_NUMBER/RANK/DENSE_RANK、LAG/LEAD、分区排序与性能优化要点,助你高效进阶数据分析!

大家好,我是小耶,写功课只是为了我踩过的坑,你们别再踩了!

很多数据分析师朋友问我:分组取前三、算累计占比、做移动平均,以前用子查询和自连接写几十行还容易错,有没有更简单的方法?有,窗口函数一行搞定。

1 名词解释

  • 窗口函数:在一组与当前行相关的行(窗口)上执行计算,不合并行,保留原数据。
  • 分区(PARTITION BY):将数据分组,窗口函数在每个分组内独立计算。
  • 排序(ORDER BY):定义窗口内行的顺序,影响排名、累计等函数的计算结果。
  • 框架(ROWS/RANGE):定义窗口的边界,如 ROWS BETWEEN 2 PRECEDING AND CURRENT ROW。

2 实际运用

2.1 三种排名函数

SELECT 
    product_id, category, sales,
    ROW_NUMBER() OVER (PARTITION BY category ORDER BY sales DESC) AS rn,
    RANK()       OVER (PARTITION BY category ORDER BY sales DESC) AS rk,
    DENSE_RANK() OVER (PARTITION BY category ORDER BY sales DESC) AS dr
FROM products;
函数 行为 示例(销售额:100,90,90,80)
ROW_NUMBER() 唯一编号,不处理并列 1,2,3,4
RANK() 并列跳号 1,2,2,4
DENSE_RANK() 并列不跳号 1,2,2,3

​
适用场景​:

  • 分页取数据 → ROW_NUMBER()
  • 比赛排名(允许并列但跳过名次) → RANK()
  • 工资等级(并列不跳过) → DENSE_RANK()

2.2 累计和与累计占比(帕累托分析)

SELECT 
    product, sales,
    SUM(sales) OVER (ORDER BY sales DESC) AS running_total,
    SUM(sales) OVER (ORDER BY sales DESC) / SUM(sales) OVER () AS cum_pct
FROM products;

2.3 移动平均(MA3)

SELECT 
    date, sales,
    AVG(sales) OVER (ORDER BY date ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) AS ma3
FROM daily_sales;

2.4 同比/环比(LAG / LEAD)

SELECT 
    date, sales,
    LAG(sales, 1) OVER (ORDER BY date) AS prev_day_sales,
    (sales / LAG(sales, 1) OVER (ORDER BY date) - 1) * 100 AS growth_rate
FROM daily_sales;

2.5 分组内百分比

SELECT 
    category, product, sales,
    sales / SUM(sales) OVER (PARTITION BY category) AS pct_in_category
FROM products;

3 性能注意事项

  • 窗口函数会在内存或磁盘中创建临时表,大量数据时注意监控 Created_tmp_disk_tables 状态。
  • ORDER BY 会触发排序,如果窗口内不需要排序可以省略 ORDER BY 提升性能。
  • MySQL 8.0及以上才支持窗口函数,低版本需要升级或用替代写法。

4 价值总结

  • 学会窗口函数,你可以将几十行的子查询+自连接改写为一行,代码简洁且性能更优。
  • 窗口函数能解决数据分析中的大部分分组统计、排名、累计计算需求,是SQL进阶的里程碑。
  • 建议先从 ROW_NUMBER() 和 SUM() OVER() 入手,再逐步掌握 RANK()、LAG() 等高级函数。

小耶在手,SQL不愁。

还有什么想了解的,欢迎留言!小耶一定知无不言言无不尽……我们下次见~

相关文章
|
4月前
|
SQL JavaScript 关系型数据库
SQL改写实战:子查询、CTE、窗口函数性能对比
本文聚焦SQL性能优化,实测对比子查询、CTE与窗口函数在复杂统计、分组排名、递归查询等场景的执行效率。基于MySQL 8.0真实数据(千万级表),揭示窗口函数在“每组取最值”“部门排名”中提速3倍以上,CTE提升可读性与递归能力,而相关子查询易成性能瓶颈。干货满满,避坑必备!
|
4月前
|
安全 Java 数据建模
【Java基础】JDK17:密封类、模式匹配、Record类(附《思维导图》+《面试高频考点清单》)
Java 17作为LTS版本,重磅引入密封类、模式匹配与Record类三大特性:Record简化不可变数据建模,密封类精准控制继承边界,模式匹配(instanceof+switch)提升类型安全与代码简洁性。三者协同可优雅实现代数数据类型,标志着Java迈向更安全、简洁、表达力更强的现代编程语言。
【Java基础】JDK17:密封类、模式匹配、Record类(附《思维导图》+《面试高频考点清单》)
|
5月前
|
SQL 关系型数据库 MySQL
InnoDB锁机制分析:为什么没有索引的UPDATE会锁全表?
本文详解“无索引为何锁全表”:InnoDB行锁依赖索引,WHERE条件无索引→全表扫描→逐行加锁→等效表锁。附排查方法与5条保命优化建议。
|
4月前
|
存储 缓存 安全
【Java基础】集合框架: ArrayList vs LinkedList 核心区别、扩容机制(附《思维导图》+《面试高频考点清单》)
本文深入解析ArrayList与LinkedList的核心差异:前者基于动态数组,支持O(1)随机访问、尾部增删高效,但中间/头部操作需移动元素;后者基于双向链表,头部/尾部增删为O(1),但随机访问O(n)且内存开销大4–5倍。重点剖析ArrayList的1.5倍扩容机制及CPU缓存优势,澄清“LinkedList更适合队列”等常见误区。
|
4月前
|
人工智能 缓存 自然语言处理
阿里云AI模型节省计划是什么?优势及优惠折扣有哪些?购买及使用指引
阿里云百炼推出AI大模型节省计划,含通用型(最高5.3折、覆盖全部直供模型)、专用型(图像/语音/向量等)及资源包三类方案,支持多地域、自动抵扣,助力企业降本增效。阿里云百炼AI大模型官网:https://t.aliyun.com/U/fPVHqY
|
4月前
|
缓存 弹性计算 应用服务中间件
高端网站搭建:Nginx 反向代理与动静分离架构配置详解
在现代企业级 Web 架构中,Nginx 凭借其极低的内存消耗和超强的高并发处理能力,成为了不可或缺的流量网关。特别是在阿里云 ECS 实例搭配 Alibaba Cloud Linux 3 的环境下,Nginx 能够充分利用操作系统的网络栈优化,实现惊人的吞吐量。 本文将详细介绍如何配置 Nginx 的反向代理与动静分离,将静态资源请求与动态接口请求完美剥离,从而大幅提升网站的整体响应速度。
|
4月前
|
人工智能 安全 搜索推荐
我用 PAI/Codex 理解 Harness Engineering:Agent 工作环境到底怎么搭
从工程师视角出发,带你过一遍 Harness Engineering
542 3
 我用 PAI/Codex 理解 Harness Engineering:Agent 工作环境到底怎么搭
|
4月前
|
存储 并行计算 安全
【Java基础】Java 8-21新特性 :Lambda表达式、函数式接口、Stream流、Optional(附《思维导图》+《面试高频考点清单》)
本文系统梳理Java 8–21核心新特性,聚焦面试高频考点:Lambda表达式、函数式接口、Stream流(惰性求值/并行流/map与flatMap区别)、Optional空值安全处理,并涵盖JDK9–21关键演进(模块化、var、Record、虚拟线程等),辅以原理剖析与实战代码,助力高效备战。
|
5月前
|
SQL 关系型数据库 MySQL
MySQL慢查询诊断实战:从10秒到0.1秒,我的5步排障法
数据库小学妹分享慢查询优化实战:从10秒降至0.08秒!详解「发现→收集→分析→优化→验证」5步排障法,覆盖慢日志配置、EXPLAIN进阶、索引失效场景、JOIN与分页优化等核心技巧,附真实案例与速查表。
|
5月前
|
关系型数据库 MySQL 测试技术
JOIN、IN、EXISTS谁最快?实测三种写法性能差异与执行计划深度剖析
本文用MySQL 8.0实测拆解`IN`/`EXISTS`/`JOIN`子查询性能:从执行计划、半连接优化、临时表开销等底层原理出发,结合10万+100万数据实测(`EXISTS`最快95ms),给出三条选型铁律——告别盲从“最佳实践”,只选最适配业务与数据的写法!