滑动平均也叫移动平均,是对一组按顺序排列的数据,取固定窗口大小的数据计算平均值,常用于时间序列数据的趋势分析,比如近7天销售额平均、近3次用户访问时长平均等场景。SQL的窗口函数天然支持这类基于顺序的聚合计算,不需要复杂的自连接就能实现滑动平均。

窗口函数滑动平均的基本语法
计算滑动平均的核心是使用AVG()聚合函数作为窗口函数,配合OVER()子句指定窗口范围,基本语法结构如下:
AVG(待计算字段) OVER (
PARTITION BY 分组字段
ORDER BY 排序字段
ROWS BETWEEN 前偏移量 PRECEDING AND 后偏移量 FOLLOWING
) AS 滑动平均字段名
其中ROWS BETWEEN ... PRECEDING AND ... FOLLOWING用来定义滑动窗口的范围,比如ROWS BETWEEN 2 PRECEDING AND CURRENT ROW表示窗口包含当前行和前2行,一共3行数据计算平均值。
具体实现示例
假设我们有一张用户访问记录表user_visit,结构如下:
| 字段名 | 类型 | 说明 |
|---|---|---|
| user_id | INT | 用户ID |
| visit_date | DATE | 访问日期 |
| visit_duration | INT | 访问时长,单位秒 |
现在需要计算每个用户每次访问时,近3次访问的平均时长,SQL实现如下:
SELECT
user_id,
visit_date,
visit_duration,
-- 计算近3次访问的平均时长,包含当前行和前2行
AVG(visit_duration) OVER (
PARTITION BY user_id
ORDER BY visit_date
ROWS BETWEEN 2 PRECEDING AND CURRENT ROW
) AS avg_recent_3_duration
FROM user_visit
ORDER BY user_id, visit_date;
如果某个用户的访问记录不足3次,窗口函数会自动取现有行数计算平均值,不会报错。比如用户只有2次访问记录,那么第二次访问的滑动平均就是这2次的平均时长。
ROWS和RANGE框架的区别
窗口函数中除了ROWS框架,还有RANGE框架,两者在计算滑动平均时的逻辑不同:
- ROWS框架:按行数划分窗口,只要排序字段的顺序确定,窗口包含的行数是固定的,和排序字段的具体值无关。
- RANGE框架:按排序字段的值范围划分窗口,比如
RANGE BETWEEN 2 PRECEDING AND CURRENT ROW,会包含所有排序字段值小于等于当前值且差值不超过2的行,行数不固定。
计算滑动平均时,通常推荐使用ROWS框架,因为滑动平均一般是基于固定次数的统计,比如近3次、近7次,而不是基于值范围的统计。
注意事项
使用窗口函数计算滑动平均时,需要注意以下几点:
- 排序字段必须明确,否则窗口内的行顺序不确定,计算结果会出错,一般时间序列场景用时间字段排序,序号场景用序号字段排序。
- 如果数据存在重复排序值,
ROWS框架会按数据读取顺序处理,RANGE框架会把所有相同排序值的行都纳入窗口,需要根据业务需求选择。 - 滑动窗口的大小需要根据业务需求确定,窗口过大会平滑掉细节,窗口过小则无法起到平滑波动的作用。
扩展场景:计算近N天滑动平均
如果需要计算近7天的滑动平均,而不是近7次的滑动平均,且日期可能存在缺失,使用RANGE框架更合适,示例如下(假设visit_date是连续或按天统计的聚合数据):
SELECT
user_id,
visit_date,
visit_duration,
-- 计算近7天(包含当天)的平均访问时长
AVG(visit_duration) OVER (
PARTITION BY user_id
ORDER BY visit_date
RANGE BETWEEN INTERVAL 6 DAY PRECEDING AND CURRENT ROW
) AS avg_recent_7day_duration
FROM user_visit
ORDER BY user_id, visit_date;
这里需要注意,不同数据库对日期范围的支持语法可能有差异,上述示例适用于MySQL 8.0及以上版本,其他数据库需要参考对应语法调整。