avg()函数对数值列求算术平均值,自动跳过null值,空结果集或全null时返回null;需用coalesce(avg(col),0)转0,分组时按group by块分别计算,不可在where中使用,精度和类型因数据库而异。

AVG() 函数的基本用法和常见报错
AVG() 是 SQL 标准聚合函数,直接对数值列求算术平均值,但它的行为在 NULL 和空结果集上容易让人踩坑。比如 SELECT AVG(score) FROM students 看似简单,但如果 score 全为 NULL 或表为空,结果会是 NULL 而不是 0 —— 这常导致前端显示异常或后续计算出错。
- 只计算非
NULL值,自动跳过NULL记录(这是正确行为,不是 bug) - 若分组后某组无有效数值(全
NULL或无匹配行),该组结果为NULL - 不能对字符串、日期等非数值类型直接使用,否则多数数据库报错如
ERROR: function avg(text) does not exist - 想把空结果转成 0,得用
COALESCE(AVG(col), 0),别写成ISNULL(AVG(col), 0)(SQL Server 才支持ISNULL,其他库不通用)
GROUP BY 下 AVG 的实际计算逻辑
很多人以为 AVG() 在分组时是“先平均再分组”,其实恰恰相反:它是按 GROUP BY 字段划分数据块,对每个块内所有非 NULL 值单独算平均。例如统计各班级平均分:SELECT class, AVG(score) FROM students GROUP BY class。
- 如果某班只有 1 条记录且
score是NULL,该班结果为NULL,不是 0 或忽略该班 - 混合类型字段(如
score存了字符串'95')可能隐式转换失败,PostgreSQL 会直接报错,MySQL 可能截断或转成 0,行为不一致 - 想排除 0 分(比如缺考记为 0),得加
WHERE score > 0,而不是在AVG()里过滤 —— 聚合函数内部不能写条件
精度丢失和类型转换陷阱
AVG() 的返回类型依赖数据库实现,但普遍倾向返回浮点数,整数列也可能被“升格”为小数,导致意外精度问题。比如 score 是 INT,AVG(score) 在 PostgreSQL 中返回 numeric,在 SQLite 中返回 REAL,而 MySQL 默认返回 DOUBLE。
- 需要保留两位小数,用
ROUND(AVG(score), 2),别依赖数据库默认输出格式 - 如果列是
DECIMAL(5,2),AVG()结果可能变成DECIMAL(10,4),超出应用层预期的位数 - 在 WHERE 或 HAVING 中不能直接用
AVG(),必须放在 SELECT 或 HAVING 子句中;写WHERE AVG(score) > 80会报错ERROR: aggregate functions are not allowed in WHERE
替代方案:手动计算平均值的适用场景
当需要控制 NULL 处理逻辑、分母是否包含 NULL 行、或跨多列加权平均时,AVG() 就不够用了。这时候得拆开分子分母自己算。
- 想把 NULL 当 0 参与计数(即分母含所有行),用
SUM(score) / COUNT(*),但要确保SUM()不为NULL(可用COALESCE(SUM(score), 0)) - 加权平均:比如
score和weight两列,用SUM(score * weight) / SUM(weight) - 避免除零错误:写成
CASE WHEN COUNT(*) = 0 THEN NULL ELSE SUM(score) / COUNT(*) END
真正麻烦的不是怎么写 AVG(),而是搞清你到底想平均什么——是有效值的均值,还是所有记录(含 NULL)的数学期望,抑或业务定义的“应考人数”下的平均。这点没理清,函数写得再对也没用。











