游乐游手机版
首页/AI教程/文章详情

SQL窗口函数进阶:滑动窗口与帧子句详解

时间:2026-06-03 12:19
上周讲了窗口函数与子查询、CTE的性能对比,有读者问:窗口函数的帧子句(ROWS RANGE)到底怎么用?为什么有时候用ROWS有时候用RANGE?今天就把这个坑填上,专门讲讲窗口函数的进阶能力——滑动窗口与帧子句。 先解释两个核心术语 什么是“滑动窗口”? 想象你站在一列数据的长队里,眼前有一个固

上周讲了窗口函数与子查询、CTE的性能对比,有读者问:窗口函数的帧子句(ROWS/RANGE)到底怎么用?为什么有时候用ROWS有时候用RANGE?今天就把这个坑填上,专门讲讲窗口函数的进阶能力——滑动窗口与帧子句。

SQL中的窗口函数进阶:滑动窗口与帧子句详解

先解释两个核心术语

什么是“滑动窗口”?

想象你站在一列数据的长队里,眼前有一个固定宽度的“窗口”,这个窗口每次向右移动一格,每次只统计窗口内的数据。比如计算最近3天的移动平均:第一天看第1-3天,第二天看第2-4天,第三天看第3-5天……窗口在“滑动”。这就是滑动窗口的核心思想:窗口位置随着当前行移动,每次计算一个范围内的数据

什么是“帧子句”?

帧子句就是用来定义这个“窗口范围”的规则。它告诉数据库:当前行的窗口应该从哪里开始、到哪里结束。比如“从当前行的前2行到当前行的后2行”“从分区第一行到当前行”。帧子句是窗口函数实现滑动窗口的关键语法。

窗口函数的核心语法是:函数() OVER (PARTITION BY ... ORDER BY ... 帧子句)。帧子句定义了相对于当前行,窗口的起止范围。用好帧子句,可以实现移动平均、累计求和、同比环比、滑动聚合等复杂逻辑,否则窗口函数就只是带排序的分组聚合而已。

一、帧子句的基本语法

帧子句的完整写法:

ROWS | RANGE BETWEEN 起点 AND 终点

其中起点和终点可以是:

  • UNBOUNDED PRECEDING:从分区第一行开始
  • n PRECEDING:当前行之前的n行
  • CURRENT ROW:当前行
  • n FOLLOWING:当前行之后的n行
  • UNBOUNDED FOLLOWING:直到分区最后一行

如果不显式指定帧子句,默认行为是:有ORDER BY时默认RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW;无ORDER BY时默认ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING。这一点经常被误解,导致计算结果与预期不符。

二、ROWS vs RANGE 的核心区别

这是最容易踩的坑。用一个比喻帮助你理解:

  • ROWS:像用“行号”画窗口。窗口按行数严格划分,不管ORDER BY列的值是否相同,每一行都独立计算。类似于“前5个人、后5个人”。
  • RANGE:像用“值”画窗口。窗口按ORDER BY列的值划分,相同值的数据必须同时出现在窗口内或被排除在外。类似于“所有年龄相同的人放在一起统计”。

用一个具体例子说明。表sales:日期和销售额

sale_dateamount
2026-01-01100
2026-01-0150
2026-01-02200
2026-01-03150

执行:

SELECT sale_date, amount,
       SUM(amount) OVER (ORDER BY sale_date ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) as rows_cum,
       SUM(amount) OVER (ORDER BY sale_date RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) as range_cum
FROM sales;

结果:

sale_dateamountrows_cumrange_cum
2026-01-01100100150
2026-01-0150150150
2026-01-02200350350
2026-01-03150500500
  • ROWS:严格按行顺序累加,第一行100,第二行100+50=150,每行都变。
  • RANGE:按sale_date的值分组。2026-01-01的两行属于同一个值,窗口把这两行作为一个整体累计,所以两行的累计值都是150(100+50),直到2026-01-02才增加到350。

实际业务中:

  • 需要严格逐行计算(如移动平均、每笔交易独立累计)→ 用ROWS
  • 需要按逻辑分组聚合(如按日期统计,同一天的数据应同时计入)→ 用RANGE

三、典型滑动窗口场景

场景1:3日移动平均(滑动窗口经典案例)

计算每个日期前后各1天(包含当天)的平均销售额。这里的“窗口”就是当前行、前1行、后1行。随着当前行向下移动,窗口也跟着“滑动”。

SELECT sale_date, amount,
       A VG(amount) OVER (ORDER BY sale_date ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) as moving_a vg_3
FROM sales;

注意边界处理:第一行没有1 PRECEDING,窗口只包含当前行和1 FOLLOWING。这就是滑动窗口最常用的形式。

场景2:从当前行到分区末尾的累计

计算每个部门内,按工资从低到高排序,从当前员工到工资最高者的工资总和。

SELECT dept, salary,
       SUM(salary) OVER (PARTITION BY dept ORDER BY salary ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) as sum_from_curr
FROM emp;

这里窗口的起点是“当前行”,终点是“分区末尾”,随着当前行下移,窗口越来越小。适合计算“比我工资高的人的总和”等需求。

场景3:排除当前行的滑动窗口

计算当前行之前2行到当前行之后2行,但排除当前行本身。例如分析整体趋势时去掉自身的波动。

SELECT sale_date, amount,
       A VG(amount) OVER (ORDER BY sale_date ROWS BETWEEN 2 PRECEDING AND 2 FOLLOWING EXCLUDE CURRENT ROW) as moving_a vg_exclude_self
FROM sales;

EXCLUDE CURRENT ROW是SQL标准支持但MySQL尚未实现的语法,PostgreSQL等数据库已支持。如果MySQL需要实现类似效果,可以自行计算总窗口值再减去当前值。

四、ROWS与RANGE在滑动窗口中的选择建议

需求场景推荐帧类型原因
时间序列移动平均(按行严格计算)ROWS不关心时间间隔是否连续,只关心行数
按日期分组统计(同一天数据一起算)RANGE相同ORDER BY值应属于同一个窗口
财务累计(按交易顺序)ROWS每笔交易独立,严格逐行累加
滚动窗口(最近7天,不关心行数)RANGE基于日期的范围,可能某天有多行或没有行

五、实际运用:计算同比环比

假设有每月销售表monthly_sales(year, month, amount)。计算环比(与上月比较):

SELECT year, month, amount,
       LAG(amount, 1) OVER (ORDER BY year, month) as prev_amount,
       (amount - LAG(amount, 1) OVER (ORDER BY year, month)) / LAG(amount, 1) OVER (ORDER BY year, month) as growth_rate
FROM monthly_sales;

LAG/LEAD函数配合帧子句可以更灵活地定义偏移量。计算同比(去年同期)则需要更复杂的窗口定义或自连接。

六、注意事项与性能建议

  • 帧子句只对聚合窗口函数(SUM、A VG、COUNT、MIN、MAX)有意义;排名函数(ROW_NUMBER、RANK等)和偏移函数(LAG、LEAD)忽略帧子句,始终基于整个分区。
  • RANGE模式要求ORDER BY列是数值或日期类型,且通常会产生比ROWS更多的内存消耗,因为需要识别“相同值”的组边界。
  • 超大窗口滑动时(如UNBOUNDED PRECEDING),相当于全分区扫描,性能开销大。可考虑使用索引和物化视图预计算。

七、总结

窗口函数的高级能力——帧子句,是实现复杂滑动分析的关键。区分ROWS与RANGE、正确设置边界,能写出更简洁高效的SQL,避免使用自连接或游标。掌握这些技巧,是SQL从“能写”到“会优化”的重要一步。

来源:https://developer.aliyun.com/article/1738165
上一篇TokenHub模型广场新人100万免费Token领取方法 下一篇严格标题输出规范:单标题限60字符30汉字
本站内容用于信息整理与展示,如有侵权或内容问题请及时联系处理。

相关推荐

补充同频道和同主题内容,方便继续浏览更多相关内容。

同类最新

继续查看同栏目最近更新的文章。

更多
2026实测解析GPT-5.5模型能力详解与国内合规使用规范
AI教程 · 2026-06-03

2026实测解析GPT-5.5模型能力详解与国内合规使用规范

2026年,AI大模型迎来了又一次迭代升级。GPT-5 5凭借在多模态精细化处理能力上的跨越式突破,正逐步成为职场办公、内容创作、代码开发以及数据优化等领域的核心生产力工具。然而,对国内多数用户而言,当前仍面临不少现实难题:渠道杂乱、合规边界模糊、账号频繁被封、数据泄露风险——各类非正规镜像站、共享

分时操作系统和实时操作系统的主要区别
AI教程 · 2026-06-03

分时操作系统和实时操作系统的主要区别

分时操作系统和实时操作系统区别 ?️ 操作系统家族里,有两类系统经常被放在一起比较:分时操作系统和实时操作系统。它们虽然都叫“操作系统”,但设计哲学、工作机制和应用场景可以说是天差地别。一个追求“公平共享”,一个追求“确定性响应”。这篇文章打算从定义、核心机制、调度策略、实际应用等维度,把这两者的本

企业AI智能体从零搭建实战踩坑经验全记录
AI教程 · 2026-06-03

企业AI智能体从零搭建实战踩坑经验全记录

去年开始用腾讯云智能体开发平台(ADP)跑了几个企业项目,从最基础的客服Bot一路干到多Agent协同系统,中间踩的坑不少,但积累下来的经验价值也相当可观。这篇文章就聊聊实际落地过程里的那些关键节点和教训,给同样在腾讯云上折腾AI Agent的朋友做个参考。为什么选腾讯云ADP而不是从零搭建做第一个

Selenium自动化测试入门:从环境搭建到首个可维护用例
AI教程 · 2026-06-03

Selenium自动化测试入门:从环境搭建到首个可维护用例

Selenium 入门的核心不在于记住多少 API,而在于把三件事想清楚:环境别装错版本、等待机制别用 sleep、用例结构别写成流水账。下面按照“装环境 → 跑通第一个脚本 → 理解等待 → 选对定位器 → 拆成 Page Object”的顺序走一遍,每一步都附上代码,踩过的坑直接标出来。 Sel

专业表格魔法师 QoderWork CN 让脏数据秒变仪表盘神器
AI教程 · 2026-06-03

专业表格魔法师 QoderWork CN 让脏数据秒变仪表盘神器

使用案例 今天聊聊怎么用阿里巴巴的 QoderWork CN 桌面应用智能体,把 Excel 里那堆乱糟糟的原始数据清洗干净,再做成可视化的看板。整个过程基本不需要写代码,全靠自然语言对话就能搞定。下面就用一个实际案例,把操作步骤拆开来讲。 步骤一:安装并注册 QoderWork CN 账号 先到