在业务数据统计中,我们常需要按某个维度分组后计算加权平均数,比如按部门计算员工绩效的加权平均分、按商品类别计算销量的加权平均单价等。加权平均数的核心计算逻辑是:先求每个数值与对应权重的乘积之和,再除以所有权重的总和。

加权平均数的基础计算逻辑
假设我们有一组数值value,对应的权重为weight,那么加权平均数的公式为:
加权平均数 = SUM(value * weight) / SUM(weight)
当需要对数据进行分组计算时,只需要在这个公式外层加上GROUP BY语句,按指定分组字段聚合即可。
通用SQL实现示例
我们先假设有一张学生成绩表student_score,表结构如下:
| 字段名 | 类型 | 说明 |
|---|---|---|
| class_id | INT | 班级ID,分组字段 |
| score | DECIMAL | 学生成绩,数值字段 |
| credit | DECIMAL | 课程学分,权重字段 |
现在需要按班级计算所有学生成绩的加权平均分,通用SQL语句如下:
-- 按班级分组计算加权平均成绩
SELECT
class_id,
-- 计算加权平均数,避免除零错误
CASE
WHEN SUM(credit) = 0 THEN 0
ELSE SUM(score * credit) / SUM(credit)
END AS weighted_avg_score
FROM student_score
GROUP BY class_id;
不同数据库的特殊处理
MySQL场景
MySQL中如果除数是整数,除法结果会自动取整,建议将其中一个值转为小数类型,避免结果精度丢失:
SELECT
class_id,
-- 将学分转为DECIMAL类型保证除法精度
SUM(score * credit) / SUM(CAST(credit AS DECIMAL(10,2))) AS weighted_avg_score
FROM student_score
GROUP BY class_id;
PostgreSQL场景
PostgreSQL中可以直接使用NUMERIC类型保证计算精度,同时支持用NULLIF函数处理除零情况:
SELECT
class_id,
-- NULLIF避免除零错误,结果为NULL时可以用COALESCE转为0
SUM(score * credit) / NULLIF(SUM(credit), 0) AS weighted_avg_score
FROM student_score
GROUP BY class_id;
注意事项
- 权重字段可能存在零值或空值,需要提前处理空值,比如用
COALESCE(weight, 0)将空权重转为0,避免计算错误。 - 如果权重总和为零,直接除法会报错,需要提前做判断,返回0或者NULL符合业务预期的结果。
- 数值和权重的乘积可能超出字段原有类型的取值范围,建议提前确认字段类型,必要时做类型转换。
加权平均数的计算逻辑适用于所有支持聚合函数的SQL数据库,核心就是先算乘积总和再除以权重总和,配合分组语句即可实现分组统计。