GROUP BY 中 AVG() 不支持权重,加权平均须用 SUM(score*weight)/NULLIF(SUM(weight),0) 手动实现,并注意 NULL 处理、除零防护与类型转换。

GROUP BY 中直接用 AVG() 无法处理权重
SQL 标准的 AVG() 函数只对值等权平均,不接受权重参数。如果你有一组数据,每行带一个权重字段(比如 score 和 weight),直接写 SELECT AVG(score) FROM t GROUP BY category 会忽略 weight,结果完全错误。
加权平均的本质是:∑(value × weight) / ∑(weight),必须手动拆解为两个聚合再相除。
正确写法:用 SUM() 手动实现加权平均
核心是把分子和分母分别聚合,再做除法。注意除法类型(避免整数截断)和空值处理:
- 分子写成
SUM(score * weight),不是AVG(score * weight) - 分母必须是
SUM(weight),不能用COUNT(*)或AVG(weight) - 如果
weight可能为 NULL 或 0,需加NULLIF(SUM(weight), 0)防止除零错误 - 推荐显式转类型,如
CAST(SUM(score * weight) AS FLOAT) / NULLIF(SUM(weight), 0),避免整数除法丢精度
示例:
SELECT category, CAST(SUM(score * weight) AS FLOAT) / NULLIF(SUM(weight), 0) AS weighted_avg FROM exam_results GROUP BY category;
WHERE 和 HAVING 对加权平均的影响很关键
过滤逻辑的位置决定结果是否符合业务预期:
-
WHERE在分组前过滤行 —— 被滤掉的行既不参与分子也不参与分母,适合剔除无效记录(如weight <= 0或score IS NULL) -
HAVING在分组后过滤组 —— 此时加权平均已算出,只能用于筛选结果,不能修正计算过程 - 常见错误:把权重校验(如
weight > 0)放到HAVING,会导致分母含 0 值,结果异常甚至报错
不同数据库对 NULL 和除零的容忍度差异大
MySQL 默认允许除零,返回 NULL;PostgreSQL 直接报错 division by zero;SQL Server 也报错。所以 NULLIF(..., 0) 不是可选优化,而是跨平台必需。
另外,若 score 或 weight 任一为 NULL,score * weight 结果为 NULL,会被 SUM() 自动忽略 —— 这行为通常合理,但得确认业务是否真想跳过这些行。必要时用 COALESCE(score, 0) 显式补零。
真正容易被忽略的是权重归一化问题:加权平均不要求权重和为 1,但如果你后续要和其他指标对比,可能需要先 SUM(weight) 看分布,确认没有极端离群权重扭曲结果。

















