ifnull只识别sql标准null,对空字符串、0等假值无效;需配合nullif将业务空转为null才能正确兜底;where中滥用可能导致索引失效;多字段fallback应选coalesce,单字段且mysql专用可选ifnull。

IFNULL只认NULL,不认空字符串和0
IFNULLIFNULL(expr1, expr2)只会检测第一个参数是否为SQL标准意义上的NULL,遇到''、0、FALSE这些“假值”完全无视——它不参与业务逻辑判断,只做NULL判定。
- 若字段存的是空字符串
'',IFNULL(name, '未知')仍返回'',不会 fallback - 若字段是数字类型且值为
0,IFNULL(age, 18)照样返回0,不会触发替换 - 真正想统一兜底“空”,得先用
NULLIF()把业务空转成NULL:IFNULL(NULLIF(phone, ''), '暂无')
别在WHERE里盲目套IFNULL,小心索引失效
IFNULL在WHERE子句中不是总能下推到引擎层。只有当表达式足够简单、且被MySQL优化器识别为可下推时,才可能利用索引。
- 安全写法:
WHERE IFNULL(status, 'draft') = 'active'—— 若status有索引,部分场景可走索引 - 危险写法:
WHERE CONCAT(IFNULL(name, ''), ' ') = '张三 '—— 函数包裹字段直接导致索引失效 - 更稳妥的替代:用
OR status IS NULL显式拆开条件,配合status = 'active'
嵌套IFNULL容易漏掉中间层的空字符串
写IFNULL(IFNULL(phone, mobile), '暂无')看似三层fallback,实则脆弱:只要phone是NULL、mobile是'',结果就是'',根本到不了第三层。
- 正确做法是逐层清洗:
IFNULL(NULLIF(phone, ''), IFNULL(NULLIF(mobile, ''), '暂无')) - 更推荐封装成生成列:
ALTER TABLE users ADD phone_display VARCHAR(20) STORED AS (IFNULL(NULLIF(phone, ''), IFNULL(NULLIF(mobile, ''), '暂无'))); - 或者建视图复用逻辑,避免每个查询都重复写这套判断
IFNULL和COALESCE选哪个?看场景和迁移计划
IFNULL快、轻量、MySQL专属;COALESCE标准、支持多参、跨库兼容——但别为了“看起来高级”就硬切。
- 只处理单个字段且确定只跑MySQL?用
IFNULL(name, '匿名'),性能略优 - 要 fallback 多个字段,比如
COALESCE(phone, mobile, email, '未提供'),必须用COALESCE - 项目未来可能迁PostgreSQL或TiDB?现在就统一用
COALESCE,省去后期批量改写 -
COALESCE会按顺序求值,前面字段非NULL就不再计算后面参数;IFNULL只算一次备选值,但仅限两个参数
IFNULL,而是字段里混着NULL、''、' '、0多种“空”,却指望一个函数全兜住。先理清数据现状,再决定要不要加NULLIF,比堆函数更省事。











