SUM()返回NULL是ANSI SQL-92标准行为,旨在区分“无数据”与“数据为零”;需据业务场景选择COALESCE(SUM(col), 0)或SUM(COALESCE(col, 0)),并注意NULL参与运算及浮点精度问题。

为什么SUM()返回NULL不是bug而是标准行为
SUM()返回NULL不是数据库实现缺陷,是ANSI SQL-92强制规定的语义:它必须区分“无数据”和“数据为零”。比如查某天订单总额,没交易就该是NULL;但用户账户余额字段为NULL,大概率是ETL异常,不该默认当0算。
常见误判是看到结果为NULL就立刻套COALESCE(),却没判断根源。三种情况处理方式完全不同:
-
WHERE条件没命中任何行 →COALESCE(SUM(col), 0)正确 - 字段本身大量为
NULL,但业务上“未填写=0” → 应该先用COALESCE(col, 0)再聚合:SUM(COALESCE(col, 0)) - 分组后某组没数据(比如某用户没订单),整行直接不出现 → 这不是
SUM()的问题,得用LEFT JOIN补全维度,或改用条件聚合:SUM(CASE WHEN status = 'paid' THEN amount ELSE 0 END)
SUM(total - discount)少算的根本原因不在SUM
写SUM(total - discount)时,只要total或discount任一为NULL,整条记录的减法结果就是NULL,再被SUM()跳过——这不是SUM()的问题,而是SQL三值逻辑决定的:任何含NULL的标量运算都返回NULL。
错误写法:SUM(total - discount) → 第4行因discount为NULL,差值变NULL,该行彻底消失
正确写法:SUM(COALESCE(total, 0) - COALESCE(discount, 0))
MySQL可简写为SUM(IFNULL(total, 0) - IFNULL(discount, 0)),但跨库迁移建议统一用COALESCE
COALESCE(SUM(col), 0)和SUM(COALESCE(col, 0))语义完全不同
这两个写法目标相似,但作用层级和业务含义天差地别,选错会导致统计失真:
COALESCE(SUM(col), 0):先聚合,再兜底。适用于“整组无数据时显示0”,比如某部门本月无销售,报表希望填0而非留空
SUM(COALESCE(col, 0)):先逐行把NULL补成0,再求和。适用于“每行都该计入,缺值即为0”,比如库存表中qty为NULL,业务定义就是“未录入=0件”
统计每日销售额 → 用COALESCE(SUM(amount), 0)
用户账户余额字段为NULL → 先确认是否属于脏数据,若是,才用SUM(COALESCE(balance, 0))
窗口函数、GROUP BY分组里同样会返回NULL
SUM(amount) OVER(PARTITION BY dept)需包一层COALESCE,否则分区内部全为NULL时照样返回NULL
分组聚合时,某组内所有amount值恰好都是NULL,SUM(amount)仍返回NULL
前端直接渲染NULL或后端调用getInt()会抛NullPointerException
金额类求和必须防浮点误差,别只盯NULL:即使你把NULL全转成0,如果字段类型是FLOAT或REAL,SUM()结果仍可能有精度偏差。金额字段建表时务必用DECIMAL(p,s),例如amount DECIMAL(12,2)

















