SQL滑动窗口聚合统计教程使用ROWS BETWEEN指定范围
在数据分析里,滑动窗口聚合是个高频操作,但也是最容易踩坑的地方之一。很多人写出来的窗口函数,乍一看语法都对,跑出来的结果却和业务直觉对不上。今天,我们就来聊聊其中最核心也最微妙的一个概念:ROWS BETWEEN。
免费影视、动漫、音乐、游戏、小说资源长期稳定更新! 👉 点此立即查看 👈

ROWS BETWEEN 是什么,它和 RANGE BETWEEN 有什么本质区别
这二者的区别,是理解窗口函数的关键。简单来说,ROWS BETWEEN 数的是“行”,它严格按照物理行位置来划定窗口边界。而 RANGE BETWEEN 看的是“值”,它根据排序键的值来分组,相同值的行会被视为一个整体。
举个例子就明白了。假设你有一张销售表,按 order_date 排序,结果集里可能有十几行记录的日期都是同一天。这时,如果你用 RANGE BETWEEN 1 PRECEDING AND CURRENT ROW 来计算“最近两天均值”,那么所有与当前行日期相同或为前一天的记录,都会被纳入计算,窗口大小可能瞬间膨胀到几十行。但如果你用 ROWS BETWEEN 1 PRECEDING AND CURRENT ROW,它就只认物理上紧挨着的前一行,窗口大小严格可控,永远是两行。
所以,一个常见的错误现象就是:当你用 A VG(sales) OVER (ORDER BY order_date RANGE BETWEEN 1 PRECEDING AND CURRENT ROW) 想算“最近两天”的均值时,在日期密集的区域,结果会剧烈跳变。因为你算的其实是“和当前日期相同或前一天的所有订单均值”,这和你想要的“时间序列上的滑动平均”根本不是一回事。
怎么写一个可靠的“过去7天销售额滚动平均”
说到滑动平均,最经典的需求莫过于“过去7天销售额的滚动平均”。这里有个关键点:时间维度不能直接用 ORDER BY date_col 配合 ROWS。为什么?因为你的原始数据里很可能有日期缺失(比如周末没销售),直接用 ROWS BETWEEN 6 PRECEDING 会错位,导致你取到的根本不是“过去7天”,而是“过去7行”。
正确的做法,得先“补全”日期。你需要一个连续的日期序列作为骨架:
- 在 PostgreSQL 里,可以用
GENERATE_SERIES函数轻松生成。 - 在 MySQL 8.0+ 或 SQL Server 里,可以用递归 CTE 来实现。
然后,用这个连续日期序列去左连接(LEFT JOIN)你的原始销售表,把缺失日期的销售额用 COALESCE(sales, 0) 补为0。最后,在这个“日期连续、数据完整”的结果集上,套用窗口函数:A VG(sales) OVER (ORDER BY dt ROWS BETWEEN 6 PRECEDING AND CURRENT ROW)。
下面是一个 PostgreSQL 的示例,思路很清晰:
SELECT dt,
sales,
ROUND(A VG(sales) OVER (ORDER BY dt ROWS BETWEEN 6 PRECEDING AND CURRENT ROW), 2) AS a vg_7d
FROM (
SELECT d.dt, COALESCE(t.sales, 0) AS sales
FROM GENERATE_SERIES('2024-01-01'::DATE, '2024-01-31'::DATE, '1 day') AS d(dt)
LEFT JOIN sales_table t ON d.dt = t.sale_date
) AS filled;
ROWS BETWEEN 的边界参数哪些能省略,哪些绝对不能省
写窗口帧的时候,边界参数怎么省是个学问。CURRENT ROW 在某些情况下可以省略,比如 ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW 可以简写成 ROWS UNBOUNDED PRECEDING。但核心原则是:起始和结束边界必须成对出现,语义才完整。
有几个容易踩的坑:
ROWS BETWEEN 2 PRECEDING—— 缺少AND ...来指定结束边界,语法直接报错。ROWS BETWEEN 1 FOLLOWING AND 1 PRECEDING—— 起始边界在结束边界之后,逻辑矛盾。PostgreSQL 会报错,而 MySQL 可能会静默地返回空值,更隐蔽。ROWS BETWEEN 5 PRECEDING AND 5 FOLLOWING—— 这种“前后各N行”的写法在首尾几行会自动截断,实际参与计算的行数会少于11行,这是符合预期的,但心里要有数。
性能影响:ROWS 越宽,执行计划越容易崩
最后,我们来谈谈性能。窗口帧的宽度,直接决定了内存占用和排序开销。当你写下 ROWS BETWEEN 10000 PRECEDING AND CURRENT ROW 这样的语句,面对百万级的结果集时,数据库引擎的压力是巨大的。PostgreSQL 可能会因为 work_mem 不足而被迫降级到磁盘排序,速度骤降;SQL Server 甚至可能直接拒绝执行,抛出一个“查询处理器无法生成查询计划”的错误。
这里有几个优化建议:
- 避免无意义的大数字:如果你本意是想取“所有前面的行”,那就直接用
UNBOUNDED PRECEDING,别写一个巨大的具体数字,这会让优化器很难做。 - 利用索引:在
ORDER BY的字段上建立索引,能让窗口计算复用排序结果,大幅降低 CPU 和内存的压力。 - 考虑替代方案:如果只是求一个简单的累计值(比如 running sum),并且数据本身就是按时间顺序入库的,有时候用应用层的流式累加来代替数据库的窗口函数,可能是更轻量、更高效的选择。
说到底,ROWS BETWEEN 的语法本身并不复杂。真正的挑战,是当它遇上稀疏的时间序列、超高基数的分组、或者超长的滑动跨度时,如何确保结果既正确无误,又能高效执行。这时候,与其盲目调大数据库的内存参数,不如回过头,好好审视一下你的数据分布和物化策略。这才是解决问题的根本。
相关攻略
戴尔笔记本开机时快速连续按F12键可调出启动菜单,选择U盘启动。若无效可尝试Fn+F12组合键或进入BIOS调整启动顺序。需确保U盘为可引导设备,若遇识别问题,可关闭BIOS中的快速启动和安全启动功能。部分新款机型需注意接口与启动模式匹配。
滑动窗口聚合中,ROWSBETWEEN按物理行数划定窗口,RANGEBETWEEN则依据排序键的值分组。计算“过去7天滚动平均”时,需先补全缺失日期生成连续序列,再使用ROWSBETWEEN确保窗口准确。边界参数须完整,避免逻辑矛盾。窗口过宽可能引发性能问题,可借助索引或替代方案优化。
在Excel中彻底删除数据行,应避免仅清空内容。建议先筛选目标行,再选中整行删除;分散数据可查找后手动勾选整行处理。批量操作时,VBA脚本应从最后一行向前遍历删除,防止漏删。完成后需清除筛选并检查行号连续性,确保数据物理删除。部分场景下,标记归档比直接删除更安全。
智度系母子公司因实控人陆宏达涉性侵指控及被羁押事件公开决裂。双方围绕法定代表人身份、公章效力及控制权展开激烈博弈,各持股东会决议互相否认对方合法性。事件导致旗下两家上市公司经营与股权稳定性面临重大不确定性,内斗持续升级且结局未定。
在Flask应用中结合HTMX实现输入框值实时更新时,针对`hx-swap`无法直接更新`value`的问题,提出两种解决方案。一是使用`outerHTML`替换整个输入框标签,后端返回完整HTML片段;二是后端返回JSON数据并通过`HX-Trigger-After-Swap`响应头触发前端JavaScript事件来精准更新值。前者无需JavaScript
热门专题
热门推荐
在软件开发与调试过程中,NullPointerException(空指针异常)是开发者经常遇到的棘手问题。系统日志中简单的“对象为null”提示,往往无法揭示问题的真正根源:是用户未登录、前端参数缺失,还是下游服务返回了空数据?这种仅呈现技术现象而丢失业务背景的异常,就是典型的异常语义丢失——底层技
《雨霖铃》改编自同名小说,以《三侠五义》为蓝本,聚焦展昭的江湖成长。该剧不仅呈现武打场面,更深入人物内心,探讨情法冲突与侠义抉择。团队坚持“手搓武侠”的匠心,注重细节与真实动作戏,为经典题材注入新活力。
mysqlbinlog工具可将二进制日志解析为可读SQL,但不能直接恢复被删除的数据。恢复关键在于定位误删前的INSERT事件并手动将其转换为可执行的INSERT语句。操作时需确认日志为ROW格式,并注意处理GTID、会话变量等干扰信息。恢复后需检查时区、字符集及外键约束等潜在问题,确保数据准确。整个过程依赖人工判断与经验。
当币铵官网无法访问时,可尝试通过官方社交媒体验证正确网址,避免点击伪装成官网的搜索广告。检查浏览器是否拦截了页面跳转,并清除缓存或更换网络。最后,确认电脑系统时间是否准确,以及浏览器是否因安全证书问题阻止了访问。
Navicat16执行ALTERTABLE时出现锁等待超时,通常因其他事务长期持有写锁。可查询INNODB_TRX和INNODB_LOCK_WAITS系统表定位阻塞源。强制KILL事务前需确认业务影响,避免数据不一致。临时方案可调高当前会话的innodb_lock_wait_timeout参数。若修改字段涉及外键约束,需先删除约束再修改字段并重建外键。





