NULL被跳过,''在多数数据库报错(如PostgreSQL),MySQL宽松模式下可能隐式转0;COUNT(col)忽略NULL但计入'',COUNT(*)两者均统计;统一预处理应先用NULLIF(col, '')转NULL再聚合。

聚合函数对 NULL 和 '' 的实际行为差异
直接写 SUM(col) 或 AVG(col) 时,NULL 被跳过,但空字符串 '' 在多数数据库里会报错(如 PostgreSQL 报 invalid input syntax for type numeric),而 MySQL 宽松模式下可能隐式转为 0 —— 这不是兼容行为,是静默偏差源头。
关键区别在于:COUNT(col) 忽略 NULL,但会计入 '';COUNT(*) 则两者都统计。这意味着同一列用不同聚合函数,结果行数可能不一致。
-
SELECT COUNT(name), COUNT(*) FROM users:若name有 10 行NULL、5 行''、85 行非空,则前者返回 90,后者返回 100 -
SUM(CAST(age AS INT))遇到''直接失败,遇到NULL则跳过 - 前端展示时,
''可能被渲染为空白,NULL渲染为NULL字样或None,混淆业务语义
统一预处理:先转 NULL 再聚合
最可控的做法不是在聚合后兜底,而是把 '' 主动转成 NULL,再让聚合函数自然跳过——这样语义清晰,且避免类型强转风险。
用 NULLIF(col, '') 是跨库标准方案,MySQL/PostgreSQL/SQL Server 均支持:
SELECT COUNT(NULLIF(phone, '')) AS valid_phone_count, AVG(NULLIF(CAST(score AS NUMERIC), '')) AS avg_score FROM students;
注意点:
-
NULLIF第二个参数必须字面量匹配,NULLIF(phone, ' ')不等于NULLIF(TRIM(phone), '') - 字符型字段做数值聚合前,务必先
NULLIF再CAST,否则''→0的隐式转换不可控 - 如果业务上“空字符串”和“NULL”代表相同含义(如“未填写”),那这一步就是必须的清洗动作
聚合后兜底:COALESCE 与方言函数的选择
聚合结果为 NULL(空组或全 NULL)时,需显式设默认值。优先用 COALESCE,它跨库、支持多参数、类型推导合理:
SELECT dept, COALESCE(SUM(salary), 0) AS total_salary, COALESCE(AVG(age), 0.0) AS avg_age FROM employees GROUP BY dept;
方言函数要谨慎:
-
IFNULL(MySQL)只接受两个参数,IFNULL(SUM(salary), IFNULL(AVG(age), 0))会报错 -
ISNULL(SQL Server)返回类型严格继承第一个参数,ISNULL(SUM(credit), 0)若credit是DECIMAL(12,4),结果仍是该精度;但COALESCE(SUM(credit), 0)会按通用规则升阶,更安全 - 别用
COALESCE(AVG(score), 'N/A')—— 类型冲突,数据库会报错或静默截断
WHERE 条件中同时排除 NULL 和 '' 的写法
想筛掉“无意义值”,不能只写 WHERE col != '',因为 NULL 比较结果是 UNKNOWN,会被 WHERE 过滤掉;也不能写 WHERE col IS NOT NULL AND col != '',这是常见但冗余的写法。
更简洁可靠的是:
WHERE NULLIF(col, '') IS NOT NULL
等价于“该列既不是 NULL,也不是 ''”。优势在于:
- 逻辑单层,可被部分数据库的索引优化器识别(尤其配合函数索引时)
- 避免 ORM 自动生成
col != '' OR col IS NOT NULL这类错误组合 - 和前面的
NULLIF处理保持风格一致,降低维护成本
真正容易被忽略的是:空字符串和 NULL 在业务语义上是否等价——如果“用户留空邮箱”和“系统未采集邮箱”要区分对待,那任何统一转 NULL 的操作都是错误的起点。

















