sum() 返回 null 而非 0,易致下游类型转换异常;count(status) 忽略 null 值,count(*) 统计全行;null 参与算术运算结果为 null,需用 coalesce 显式处理;业务语义不明时盲目补 0 风险更大。

SUM() 返回 NULL 而不是 0,程序取值时容易炸
当 SUM() 遇到全 NULL 或无匹配行时,结果是 NULL,不是数值 0。很多 JDBC、ORM(如 MyBatis 的 resultType="int")或 Python pandas 直接调 getInt() / int() 会抛空指针或类型错误。
- 错误写法:
SUM(amount)→ 结果为NULL,下游代码未判空直接强转就崩 - 安全写法:
COALESCE(SUM(amount), 0),确保返回整数类型 - 注意:如果业务上需要区分“无数据”和“有数据但为零”,就不能盲目补 0,得保留
SUM()原始NULL并在应用层显式处理
COUNT(status) 和 COUNT(*) 差出几千条,不是 bug 是语义
COUNT(status) 只统计 status IS NOT NULL 的行;COUNT(*) 统计所有行。若表里有 5% 的 status 是 NULL,用前者统计“总订单数”就天然少算 5%。
- 典型场景:订单状态字段未设默认值,新建订单没赋值,存入
NULL;但 BI 报表却用COUNT(status)当总单量 - 查漏方法:
SELECT COUNT(*), COUNT(status), COUNT(*) - COUNT(status) AS null_count FROM orders - 修复动作:建表时加
status VARCHAR(20) NOT NULL DEFAULT 'created',或聚合前统一清洗:COUNT(COALESCE(status, 'unknown'))
SUM(total - freeze) 少算,问题不在 SUM,在减法本身
total_amount 或 freeze_amount 任一为 NULL,整个 total - freeze 表达式就是 NULL,再喂给 SUM() 就被跳过——这不是聚合函数的问题,是 SQL 三值逻辑的必然结果。
- 错误链:
1000 - NULL → NULL → SUM() 忽略这一行 - 正确写法:
SUM(COALESCE(total_amount, 0) - COALESCE(freeze_amount, 0)) - 更严谨的做法:先确认业务含义——
freeze_amount IS NULL真的是“冻结为 0”,还是“冻结状态未知”?后者补 0 就歪曲事实
真正难处理的不是 NULL 本身,而是它混在业务语义里不露声色:同一张表中,有的 NULL 表示“未发生”,有的表示“不适用”,有的表示“尚未录入”。这时候光靠 COALESCE(col, 0) 一刀切,比不处理还危险。











