在业务数据统计中,加权平均值比普通平均值更能反映数据的实际权重占比,当计算所需的基础数据需要通过子查询获取时,就需要结合嵌套SUM与PRODUCT函数实现计算逻辑。加权平均值的核心公式是所有数值乘以对应权重的总和,再除以所有权重的总和,这个逻辑在SQL中可以通过聚合函数拆分实现。

加权平均值的计算逻辑拆解
假设我们有数值列score和对应的权重列weight,加权平均值公式为:
加权平均值 = SUM(score * weight) / SUM(weight)
这里的score * weight就是每个数值的加权值,总和除以权重总和后得到最终结果。当score和weight的数据需要从子查询获取时,就需要先通过子查询筛选出符合要求的基础数据,再在外层查询中完成聚合计算。
子查询与嵌套SUM、PRODUCT的使用方法
基础实现示例
以下示例先通过子查询获取学生成绩和对应课程学分,再计算加权平均分:
-- 子查询获取学生课程成绩和对应学分
SELECT
SUM(s.weighted_score) / SUM(s.credit) AS weighted_avg
FROM (
-- 子查询:关联成绩表和课程表,计算单门课程的加权值
SELECT
sc.score * c.credit AS weighted_score,
c.credit
FROM student_course sc
INNER JOIN course c ON sc.course_id = c.course_id
WHERE sc.student_id = 1001
) s
上面的子查询中,sc.score * c.credit就是单门课程的加权值,外层查询通过SUM函数分别求和后做除法,得到最终的加权平均分。
使用PRODUCT函数的场景
如果权重是多个因子的乘积,比如需要结合课程难度系数和学分两个权重因子,就可以用到PRODUCT函数:
SELECT
SUM(s.score * s.total_weight) / SUM(s.total_weight) AS weighted_avg
FROM (
SELECT
sc.score,
-- 计算组合权重:学分乘以难度系数
PRODUCT(c.credit, c.difficulty) AS total_weight
FROM student_course sc
INNER JOIN course c ON sc.course_id = c.course_id
WHERE sc.student_id = 1001
GROUP BY sc.score, c.credit, c.difficulty
) s
注意PRODUCT函数在部分数据库中不直接支持,比如MySQL没有内置PRODUCT函数,可以通过对数求和再取指数的方式实现,示例如下:
-- MySQL实现多权重因子乘积
SELECT
SUM(s.score * s.total_weight) / SUM(s.total_weight) AS weighted_avg
FROM (
SELECT
sc.score,
-- 利用对数计算乘积:EXP(SUM(LN(因子1)) + SUM(LN(因子2)))
EXP(SUM(LN(c.credit)) + SUM(LN(c.difficulty))) AS total_weight
FROM student_course sc
INNER JOIN course c ON sc.course_id = c.course_id
WHERE sc.student_id = 1001
GROUP BY sc.score
) s
常见注意事项
- 子查询中需要确保返回的加权值和权重列没有NULL值,否则SUM函数会忽略NULL,导致计算结果偏差,可以通过
COALESCE函数处理NULL值。 - 除法计算时注意数据类型,如果都是整数类型,部分数据库会做整数除法截断小数,需要转换为浮点型,比如
SUM(s.weighted_score) * 1.0 / SUM(s.credit)。 - 如果子查询中有分组逻辑,要确保分组字段和外层聚合逻辑匹配,避免出现数据重复计算的问题。
错误写法示例
以下是错误的实现方式,直接在子查询中计算加权平均值再取平均,会导致结果错误:
-- 错误写法:先算单门加权再平均,不符合加权平均值公式
SELECT AVG(s.weighted_avg) AS wrong_avg
FROM (
SELECT
sc.score * c.credit / SUM(c.credit) AS weighted_avg
FROM student_course sc
INNER JOIN course c ON sc.course_id = c.course_id
WHERE sc.student_id = 1001
) s
这种写法没有先求和所有加权值再除以权重总和,而是先对单条数据做除法再平均,不符合加权平均值的计算逻辑,会得到错误结果。