聚合函数天然忽略null而非视作0:sum/avg/max/min跳过null,整列null时返回null;coalesce(sum(c),0)先聚合后兜底,sum(coalesce(c,0))先补零后聚合,语义不同。

聚合函数天然忽略NULL,不是当0处理
这是最常被误解的一点:SUM、AVG、MAX、MIN这些函数遇到NULL时,不是把它当成0去算,而是直接跳过——整行数据在聚合阶段就被筛掉了。比如表里有[10, NULL, 20],SUM(col)结果是30,看起来没问题;但如果是[NULL, NULL],结果就是NULL,不是0。报表取值时直接崩,前端显示空白或报错。
更隐蔽的问题是空结果集:SELECT MAX(id) FROM empty_table不返回任何行,但MAX()仍会返回一个NULL单行结果,导致@@ROWCOUNT为1而非0,后续逻辑判断彻底失效。
COALESCE(SUM(col), 0) 和 SUM(COALESCE(col, 0)) 完全不同
这两个写法语义相反,选错就统计失真:
-
COALESCE(SUM(col), 0):先聚合,再把聚合结果的NULL兜底成0。适用于“空组也要显示0”的报表场景。 -
SUM(COALESCE(col, 0)):先把每行的NULL转成0,再求和。适用于“没填=0元”的业务规则。
举个例子:[NULL, 100] —— 前者得NULL → 0,后者得0 + 100 = 100。别用AVG(COALESCE(salary, 0)),它会让平均值虚高。
WHERE里用COALESCE可能让索引失效
想查“status是active或空值”,别写WHERE COALESCE(status, 'active') = 'active'。数据库无法用索引匹配函数结果,全表扫描就来了。
正确做法是拆开写:WHERE status = 'active' OR status IS NULL,能走索引;或者预处理变量:DECLARE @filter_status VARCHAR(20) = COALESCE(@status, 'active'),再用WHERE status = @filter_status。
触发器和字符串拼接里NULL更危险
CONCAT('ID:', id, '-', name)只要id或name任一为NULL,整个结果就是NULL。这不是bug,是标准行为。
必须全字段包住:CONCAT('ID:', COALESCE(id, ''), '-', COALESCE(name, ''))。别漏掉任何一个参与拼接的字段,漏一个就全崩。
跨库迁移时优先用COALESCE,它是SQL标准函数;ISNULL是SQL Server专属,IFNULL只在MySQL里有效——写错一个,存储过程上线就报错。











