首页/数据/SQL 速查/移动平均
聚合与窗口函数54 条

移动平均

用窗口帧计算近 N 行均值(如近 7 天平均销量),平滑波动;帧写法 ROWS BETWEEN 6 PRECEDING AND CURRENT ROW。

SQL 速查数据更新于 2026-10-13

移动平均是什么

移动平均用窗口函数在「当前行加上前面 N-1 行」上求平均,把日度波动抹平,用来观察趋势。关键是帧的定义:ROWS BETWEEN 4 PRECEDING AND CURRENT ROW 严格按行数取最近 5 行;RANGE 按值范围取,且会把并列值一起纳入。窗口开头的几行数据不足,按已存在的行求平均,不会补 NULL。MySQL 8 与 PostgreSQL 都支持这种写法,列上还需注意窗口里的 ORDER BY 是帧定义的一部分。

基本信息

适用平台MySQL 8.0+ / PostgreSQL 11+
默认帧带 ORDER BY 且未写帧子句时是 RANGE UNBOUNDED PRECEDING 到当前行,即累计平均
移动平均写法ROWS BETWEEN 6 PRECEDING AND CURRENT ROW 表示含当前行共 7 行
与累计平均区别移动平均只看固定长度窗口,累计平均从开头算到当前行
边界处理开头行窗口不足时按现有行计算,需要「窗口完整才输出」时用 COUNT 判断

典型使用场景

  • 7 日/30 日均线观察业务趋势,避免单日波动误判
  • 平滑转化率、客单价等指标的噪声
  • 监控告警去噪:用移动平均替代单点阈值
  • 报表里同时给出日值与均线,便于人工判断
  • 与环比结合,看趋势是在加速还是回落

基础写法

基础写法
SELECT d, amount,
       AVG(amount) OVER (ORDER BY d ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) AS ma7,
       AVG(amount) OVER (ORDER BY d)                                          AS cum_avg
FROM daily_stats
ORDER BY d;

# ma7:含当前行共 7 行的平均,开头行按现有行计算
# cum_avg:默认帧是 RANGE UNBOUNDED PRECEDING,等于累计平均

按维度分别计算

按维度分别计算
-- 每个门店各自算 7 日移动平均
SELECT shop_id, d, amount,
       ROUND(AVG(amount) OVER (PARTITION BY shop_id
                               ORDER BY d
                               ROWS BETWEEN 6 PRECEDING AND CURRENT ROW)::numeric, 2) AS ma7,
       COUNT(*) OVER (PARTITION BY shop_id
                      ORDER BY d
                      ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) AS window_rows   # 可用于判断窗口是否完整
FROM daily_stats
ORDER BY shop_id, d;

常用帧写法对照

帧定义含义典型用途
默认(带 ORDER BY)RANGE UNBOUNDED PRECEDING 到当前行累计值、累计平均
ROWS BETWEEN 6 PRECEDING AND CURRENT ROW固定 7 行7 日移动平均
ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING前后各一行共 3 行三点平滑
RANGE BETWEEN INTERVAL '6 days' PRECEDING AND CURRENT ROW按时间范围的 7 天日期有缺失时更贴近日历口径
日期存在缺失时 ROWS 与 RANGE 结果不同:ROWS 凑够 7 行(可能跨越多天),RANGE 按时间范围取(可能不足 7 行);按日历天定义口径的业务指标应选 RANGE,或先把日期序列补齐。
窗口里的 ORDER BY 是帧定义的一部分,不是输出排序:只写 AVG(x) OVER () 会变成对全分区求平均,每行结果都一样,看起来「算出来了」其实完全不是移动平均。

易错点

  • 漏写帧子句,得到的是累计平均却被当成移动平均使用
  • 同一时间存在多条记录时使用 RANGE 帧,并列值被一起纳入,窗口实际超过预期行数
  • 数据有缺失日期却用 ROWS 帧,「7 行」可能跨越远多于 7 天
  • 窗口里忘写 ORDER BY,全分区一个平均值,趋势全部被抹平

数据来源与参考

  • MySQL 8.0 Reference Manual · Window Function Frames
  • PostgreSQL Documentation · Window Functions
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌