avg()底层等价于sum(col)/count(col),当col为整型时,整数除法会截断小数导致精度丢失;必须显式转decimal或乘1.0提升精度,否则round等后续操作无法恢复已丢精度。

AVG() 本身不执行除法运算,但它的底层实现依赖 SUM() 和 COUNT() 的商——而这个商在多数数据库中会触发整数除法规则,这才是精度丢失的真正源头。
AVG() 的除法本质藏在 SUM() / COUNT() 里
AVG(col) 等价于 SUM(col) / COUNT(col),不是黑盒函数。当 col 是整型(如 INT),SUM(col) 和 COUNT(col) 都返回整型,整个表达式就按整数除法规则执行:
-
SUM(3, 5, 7) = 15,COUNT() = 3→15 / 3 = 5✅ -
SUM(1, 2) = 3,COUNT() = 2→3 / 2 = 1❌(期望是1.5)
这个截断发生在除法计算那一瞬,后续加 ROUND(, 2) 或 CAST(... AS DECIMAL) 都无法恢复已丢失的小数部分。
不同数据库对 AVG() 结果类型的处理差异
- MySQL 5.7:输入为
INT,结果默认仍是DECIMAL(10,0)(即无小数位) - PostgreSQL:返回
NUMERIC,但精度由输入推导,INT输入可能只给 0 小数位 - SQL Server:
AVG(INT)返回DECIMAL(10,0),和 MySQL 类似 - SQLite:直接整数除法,
3/2=1,且不支持类型声明干预
关键点:不能指望数据库“自动升级精度”,必须主动干预输入或中间值类型。
怎么写才让 AVG() 返回带小数的结果
- 最通用、零兼容风险的写法:
AVG(CAST(col AS DECIMAL(15,2))) - 如果只是临时修正(如调试),可改用显式除法:
SUM(col) * 1.0 / COUNT(col) - PostgreSQL 支持更精准的语法:
AVG(col::NUMERIC) - 别用
AVG(CAST(col AS FLOAT)):浮点误差会污染财务类计算
注意:如果 col 本身含 NULL 或非数值字符串,CAST 会报错,需前置清洗或用 FILTER(PostgreSQL)或 WHERE col ~ '^[0-9.+-eE]+$'(MySQL)兜底。
最常被忽略的是:你以为在调 AVG(),其实你在默许一次隐式整数除法。它不报错,不警告,只悄悄把 4.9 变成 4——而你直到报表对不上账才回头找它。











