SQL中如何实现每3行数据计算一次平均值?

SQL实现每3行计算平均值方案
SQL中表本身是无序集合,所以所有计算的前提是先指定明确的排序字段(比如自增主键、业务时间戳),否则行顺序不确定,计算结果没有意义。下面分两种最常见的需求场景给出可直接复用的代码:
场景1:滚动计算连续3行的平均值
即每一行的结果为「当前行+前2行」的均值,前2行不足3行时按实际存在的行数计算,适合做趋势平滑场景。
支持窗口函数的数据库(MySQL 8.0+、PostgreSQL、SQL Server、Oracle、Hive、Spark SQL等)直接用窗口函数实现,性能最好:
SELECT *, AVG(要计算均值的数值字段) OVER ( ORDER BY 你的排序字段 -- 替换为实际的排序字段,比如id、stat_time ROWS BETWEEN 2 PRECEDING AND CURRENT ROW ) AS rolling_avg_3rows FROM 你的业务表名;
如果要求必须凑够3行才返回结果,不足3行的前两行返回空,加个行号判断即可:
SELECT *, CASE WHEN ROW_NUMBER() OVER (ORDER BY 你的排序字段) >= 3 THEN AVG(要计算均值的数值字段) OVER ( ORDER BY 你的排序字段 ROWS BETWEEN 2 PRECEDING AND CURRENT ROW ) END AS rolling_avg_3rows FROM 你的业务表名;
场景2:每3行分为固定一组,计算组内平均值
即第1-3行为第一组、4-6行为第二组,以此类推,同组所有行共享同一个平均值。
支持窗口函数的数据库写法:
WITH ranked_table AS ( SELECT *, ROW_NUMBER() OVER (ORDER BY 你的排序字段) AS row_num FROM 你的业务表名 ) SELECT *, AVG(要计算均值的数值字段) OVER (PARTITION BY CEIL(row_num / 3)) AS group_avg_3rows FROM ranked_table;
如果是MySQL 5.x这类不支持窗口函数的老版本,用用户变量生成行号后关联计算即可:
SELECT t1.*, AVG(t2.要计算均值的数值字段) AS group_avg_3rows FROM ( SELECT @rn := @rn + 1 AS row_num, -- 此处替换为你实际需要查询的字段 id, stat_time, value FROM 你的业务表名, (SELECT @rn := 0) init ORDER BY 你的排序字段 ) t1 INNER JOIN ( SELECT @rn2 := @rn2 + 1 AS row_num, 要计算均值的数值字段 FROM 你的业务表名, (SELECT @rn2 := 0) init ORDER BY 你的排序字段 ) t2 ON CEIL(t2.row_num / 3) = CEIL(t1.row_num / 3) GROUP BY t1.row_num, t1.id, t1.stat_time, t1.value;
替换代码参数时注意:排序字段必须是能唯一确定行顺序的非空字段,不要用有重复值的字段排序,否则会出现行号重复、计算偏差的问题。
内容的提问来源于stack exchange,提问作者ignesiyasLoyala
相关产品推荐
相关产品推荐

