当前位置: 首页 > article >正文

SQL 实战:窗口函数进阶 – 实现复杂滑动窗口与动态累计计算

窗口函数是 SQL 中非常强大的工具,能够在不改变原始数据粒度的情况下,动态进行排名、累计、滑动平均以及环比同比计算。
在实际业务场景中,窗口函数常用于构建复杂的时间序列分析,如滚动累计、移动平均、同比/环比增长等。

本文将深入探讨窗口函数的高级用法,通过具体案例展示如何利用 LAG()LEAD()NTILE()CUME_DIST() 解决滑动窗口和动态累计计算问题。


一、窗口函数回顾与高级函数简介

1. 窗口函数核心概念
  • 窗口函数 是一种在结果集中按分区按顺序对数据进行计算的函数,返回的结果与原始表数据具有相同的行数。
  • 与聚合函数不同,窗口函数不折叠行,而是在每一行上执行计算。

2. 常用窗口函数及其功能
函数说明示例
ROW_NUMBER()为每个分区内的行分配唯一编号,从 1 开始递增ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY date)
RANK()类似于 ROW_NUMBER(),但排名相同则跳过名次RANK() OVER (ORDER BY score DESC)
DENSE_RANK()连续排名,不跳过DENSE_RANK() OVER (ORDER BY amount DESC)
LAG()获取当前行前 N 行的值LAG(amount, 1) OVER (PARTITION BY user_id ORDER BY date)
LEAD()获取当前行后 N 行的值LEAD(amount, 1) OVER (ORDER BY date)
NTILE(n)将分区数据分为 nNTILE(4) OVER (ORDER BY score)
CUME_DIST()累积分布,计算小于等于当前行的比例CUME_DIST() OVER (PARTITION BY category ORDER BY price)

二、实战案例:滑动窗口与动态累计计算


案例 1:计算滚动 3 个月的销售额总和

需求描述
在电商系统中,按月份统计用户的订单销售额,并计算滚动 3 个月的累计销售额


表结构 sales
sale_iduser_idsale_dateamount
11012024-01-01500
21012024-02-01600
31012024-03-01700
41012024-04-01800
51012024-05-01400
61022024-01-01300
71022024-03-01500
81022024-04-01600

SQL 实现
SELECT user_id,  
       sale_date,  
       amount,  
       SUM(amount) OVER (
           PARTITION BY user_id  
           ORDER BY sale_date  
           ROWS BETWEEN 2 PRECEDING AND CURRENT ROW
       ) AS rolling_3m_sum  
FROM sales;

查询结果
user_idsale_dateamountrolling_3m_sum
1012024-01-01500500
1012024-02-016001100
1012024-03-017001800
1012024-04-018002100
1012024-05-014001900
1022024-01-01300300
1022024-03-01500800
1022024-04-016001400

解释

  • ROWS BETWEEN 2 PRECEDING AND CURRENT ROW 定义了一个滚动窗口,包含当前行及前两行的数据。
  • SUM(amount) 在该窗口内累计销售额,形成滚动 3 个月销售额总和


案例 2:计算同比增长率

需求描述
统计每个用户按月份的销售额,并计算与上个月相比的销售增长率(环比)同比增长率(去年同月)


SQL 实现
SELECT user_id,  
       sale_date,  
       amount,  
       LAG(amount, 1) OVER (
           PARTITION BY user_id  
           ORDER BY sale_date
       ) AS prev_month_amount,  
       ROUND((amount - LAG(amount, 1) OVER (
           PARTITION BY user_id ORDER BY sale_date
       )) / LAG(amount, 1) OVER (
           PARTITION BY user_id ORDER BY sale_date
       ) * 100, 2) AS month_growth_rate  
FROM sales;

查询结果
user_idsale_dateamountprev_month_amountmonth_growth_rate
1012024-01-01500NULLNULL
1012024-02-0160050020.00%
1012024-03-0170060016.67%
1012024-04-0180070014.29%
1012024-05-01400800-50.00%

解释

  • LAG() 函数获取前一行的销售额,用于计算环比增长率。
  • ROUND() 保留两位小数,NULL 表示首月无前一月数据。


案例 3:按销售额分位排名(四分位数)

需求描述
将用户的销售额按四分位数进行排名(将用户数据分为 4 组,每组约占 25%)。


SQL 实现
SELECT user_id,  
       amount,  
       NTILE(4) OVER (
           ORDER BY amount DESC
       ) AS quartile  
FROM sales;

查询结果
user_idamountquartile
1018001
1017001
1016002
1015002
1025003
1024003

解释

  • NTILE(4) 将数据平均分为 4 份,金额最高的前 25% 用户归为第 1 组,依次类推。

总结

  • 滑动窗口滚动累计常用于时间序列分析,如销售额、活跃用户等。
  • 使用 LAG()LEAD() 可以轻松实现环比和同比计算。
  • NTILE()CUME_DIST() 是分布分析的利器,适合用户分层和分位排名场景。

http://www.kler.cn/a/458820.html

相关文章:

  • c++表达范围勿用数学符号
  • 计算机网络-L2TP VPN基础实验配置
  • WebRTC的三大线程
  • 六年之约day3
  • 2024-12-29-sklearn学习(26)模型选择与评估-交叉验证:评估估算器的表现 今夜偏知春气暖,虫声新透绿窗纱。
  • 0055. shell命令--useradd
  • 大数据与机器学习(它们有何关系?)
  • Mac电脑python多版本环境安装与切换
  • Selenium之Web元素定位
  • Android笔试面试题AI答之Android基础(7)
  • hive-sql 连续登录五天的用户
  • 【GeekBand】C++设计模式笔记18_State_状态模式
  • 【2024年-6月-21日-开源社区openEuler实践记录】探索 intel-kernel:英特尔架构内核优化之路
  • [TOTP]android kotlin实现 totp身份验证器 类似Google身份验证器
  • 环,域,体,整区,理想,极大理想,
  • 配置hive支持中文注释
  • Lombok是银弹?还是陷阱?
  • golang标准库archive/tar实现打包压缩及解压
  • 《Java核心技术 卷II》流的创建
  • Vue el-data-picker选中开始时间,结束时间自动加半小时
  • 滑动窗口、流量控制和拥塞控制
  • C++笔记-对windows平台上lib和dll的进一步理解(2024-10-21
  • YOLOv8实战车辆目标检测
  • js混淆中 p[‘name‘] 来访问属性的好处
  • 若依前后端分离项目部署(使用docker)
  • C++ 设计模式:职责链模式(Chain of Responsibility)