加权平均不能直接用AVG()函数,因其仅计算算术平均而忽略权重;正确公式为SUM(值×权重)/SUM(权重),需用NULLIF避免除零,且权重应过滤非正数。

加权平均为什么不能直接用 AVG() 函数
AVG() 只对值做简单算术平均,完全忽略权重。比如你有一组商品销量和对应利润率,想算“整体利润率”,就不能把利润率 AVG() 一下了事——高销量商品该占更大比重。真实业务中,AVG() 在加权场景下会给出错误结果,且无法通过 GROUP BY 或窗口函数绕过这个本质限制。
SUM(值 * 权重) / SUM(权重) 的写法与常见错误
核心公式必须拆成两部分计算:分子是各条记录的「值 × 权重」之和,分母是「权重」之和。直接写 SUM(值 * 权重) / SUM(权重) 即可,但要注意:
- 权重列不能含
NULL,否则整行参与计算时会导致分子或分母为NULL,最终结果为NULL - 避免在分母上写
SUM(COALESCE(权重, 0))——这会让权重为 0 的记录拉低分母,造成除零或数值失真;正确做法是先过滤或用NULLIF(SUM(权重), 0) - 如果权重是百分比(如 0.15、0.85),公式依然成立,但需确认它们总和是否为 1——不是也没关系,公式本身不要求归一化
示例(MySQL/PostgreSQL 兼容):
SELECT SUM(sales_amount * profit_rate) / NULLIF(SUM(sales_amount), 0) AS weighted_profit_rate FROM orders WHERE sales_amount > 0;
处理权重为 0 或负数的边界情况
权重为 0 意味着该记录不应参与加权平均;负数权重在数学上可能有意义(如对冲场景),但多数数据库不报错,却会扭曲结果。务必在 WHERE 中显式约束:
- 用
WHERE weight > 0排除无效权重(最常用) - 若业务允许负权重,需确认分母
SUM(weight)不为 0,否则除法无定义——NULLIF是必须的 - 不要依赖
HAVING SUM(weight) > 0做事后校验,它无法阻止除零警告(尤其在 PostgreSQL 中会抛division by zero错误)
在窗口函数中复用加权逻辑
想按部门分别计算加权利润率?不能只套 OVER(PARTITION BY dept) 到整个表达式外——那样会语法错误。必须把 SUM() 显式写成窗口函数:
SELECT dept, SUM(sales_amount * profit_rate) OVER (PARTITION BY dept) / NULLIF(SUM(sales_amount) OVER (PARTITION BY dept), 0) AS dept_weighted_rate FROM orders WHERE sales_amount > 0;
注意:SUM(...) OVER 和普通 SUM() 在同一查询中可共存,但语义不同;漏掉任一 OVER 就会变成全局聚合,导致每行结果相同。
复杂点在于,一旦涉及多层分组或需要同时输出简单平均与加权平均,子查询或 CTE 就很难绕开——没有更短的单行解法。










