SQL中加权平均值的正确写法是SUM(值*权重)/SUM(权重),必须显式计算乘积项并分组聚合,配合NULLIF防除零,且需注意NULL、零权重及浮点精度问题。

SQL里加权平均值的正确写法是 SUM(值 * 权重) / SUM(权重),不是 SUM(权重值) / SUM(权重)
很多人误把“权重值”当成一个字段名,其实它并不存在——加权平均的核心是每个观测值要先乘以其对应权重,再整体求和。直接写 SUM(权重值) 会报错或返回空/0,因为数据库找不到这个列。关键在于:必须显式写出 值 * 权重 这个乘积项。
GROUP BY 场景下必须同时 SUM(值 * 权重) 和 SUM(权重)
分组后每组要独立算自己的加权平均,不能只用全局总和。常见错误是漏掉 SUM(权重) 或错写成 COUNT(*)——后者在权重不为1时完全失真。
SELECT category, SUM(score * weight) / SUM(weight) AS weighted_avg FROM exams GROUP BY category;- 如果某组中所有
weight都为NULL,SUM(weight)返回NULL,整除结果也是NULL,需用NULLIF防止除零错误 - PostgreSQL/MySQL 8.0+/SQL Server 支持
NULLIF(SUM(weight), 0);SQLite 要改用CASE WHEN SUM(weight) = 0 THEN NULL ELSE ... END
NULL 值和零权重必须显式处理
score 或 weight 任一为 NULL,乘积就是 NULL,会被 SUM 自动忽略——这看似合理,但容易掩盖数据质量问题。更危险的是 weight = 0:它参与了分母计算,却让分子贡献为0,拉低均值却不报警。
- 建议过滤掉
weight 的行:WHERE weight > 0 AND score IS NOT NULL - 若业务允许零权重,分母应改为
NULLIF(SUM(NULLIF(weight, 0)), 0),避免除零 - 别依赖
COALESCE(weight, 1)补默认值——这会扭曲原始权重结构
性能与精度注意点:用 DECIMAL 而非 FLOAT 存权重
浮点数在累加时有精度误差,尤其当权重含小数(如 0.3、0.7)且行数多时,SUM(weight) 可能变成 0.999999999,导致除法结果偏移。金融、教育评分等场景必须规避。
- 建表时定义权重列为
DECIMAL(5,3)(如 0.001~99.999),而非FLOAT或REAL - MySQL 中
CAST(score AS DECIMAL) * CAST(weight AS DECIMAL)可强制中间计算精度 - BigQuery/Redshift 等分析型数据库对
NUMERIC更友好,优先选它
加权平均本身不复杂,但分组 + NULL + 浮点 + 零权重这四个因素叠在一起,很容易跑出看似合理实则错误的结果。动手前先查查 weight 列里有没有 0、NULL、负数,比调公式花的时间还值。










