IFNULL 与 ISNULL 是什么
IFNULL(a, b) 是 MySQL 的二元函数:a 不为 NULL 就返回 a,否则返回 b,专门做空值替换。容易混淆的是 ISNULL(a) 在 MySQL 里是一元判断函数,返回 1 或 0,只判断不替换;而 SQL Server 的 ISNULL(a, b) 才是替换语义——同名不同义,跨库搬代码最容易踩这里。跨库对应关系:PostgreSQL 用 COALESCE(标准函数,支持多参数),Oracle 用 NVL,因此写可移植 SQL 时优先选 COALESCE。
基本信息
| MySQL 替换 | IFNULL(a, b),只接受两个参数 |
|---|---|
| MySQL 判断 | ISNULL(a) 返回 1 或 0,仅做判空 |
| SQL Server | ISNULL(a, b) 是替换语义,与 MySQL 的 ISNULL 完全不同 |
| PostgreSQL | COALESCE(a, b, …),支持多参数,取第一个非 NULL 值 |
| Oracle | NVL(a, b);COALESCE 同样可用 |
| 判空写法 | 一律用 IS NULL / IS NOT NULL,不能写 = NULL |
典型使用场景
- 展示层把 NULL 换成业务默认文案(「未填写」「暂无」)
- 汇总计算兜底为 0,避免报表出现空格
- 字符串拼接前兜底,防止整列结果因一个 NULL 变成 NULL
- 数值差值计算时避免 NULL 传播
- 数据清洗阶段给缺失字段补默认值
- 与 NULLIF 组合,把空字符串统一转成 NULL 再兜底
MySQL 用法
MySQL 用法
# 逐行替换与判空
SELECT IFNULL(name, '未填写') AS name_filled, # NULL 时显示默认文案
ISNULL(name) AS is_null_flag, # MySQL 里返回 1/0 的判断函数
NULLIF(name, '') AS empty_to_null # 空串转 NULL,常与兜底搭配
FROM users WHERE id = 1;
# 聚合兜底:没有匹配行时返回 0 而不是空
SELECT IFNULL(SUM(amount), 0) AS total
FROM orders
WHERE order_date = CURDATE();跨库可移植写法
跨库可移植写法
-- COALESCE 在 MySQL、PostgreSQL、SQL Server、Oracle 上都可用,且支持多参数
SELECT COALESCE(nickname, real_name, '匿名用户') AS shown_name,
COALESCE(SUM(amount), 0) AS total
FROM users u
LEFT JOIN orders o ON o.user_id = u.id
GROUP BY u.id;跨库函数对照
| 目标 | MySQL | PostgreSQL | SQL Server | Oracle |
|---|---|---|---|---|
| 替换 NULL | IFNULL(a,b) | COALESCE(a,b) | ISNULL(a,b) | NVL(a,b) |
| 判断是否 NULL | ISNULL(a) 返回 1/0 | a IS NULL | a IS NULL | a IS NULL |
| 多参数兜底 | COALESCE 支持 | COALESCE 支持 | COALESCE 支持 | COALESCE 支持 |
| 空串转 NULL | NULLIF(a,'') | NULLIF(a,'') | NULLIF(a,'') | NULLIF(a,'') |
| 多级兜底 | IFNULL 需嵌套,不推荐 | COALESCE(a,b,c) | COALESCE(a,b,c) | COALESCE(a,b,c) |
可移植性建议:优先用 COALESCE,四大数据库都提供且支持任意多个参数;IFNULL 与 NVL 属于方言,ISNULL 在 MySQL 与 SQL Server 里含义还完全不同,跨库脚本应避免使用。
兜底会掩盖数据问题:用 IFNULL 把 NULL 显示成 0 之后,无法再区分「确实为 0」与「没有数据」;做对账或告警时应在 SQL 里额外输出判空标记,而不是只输出兜底值。
需要多级兜底时不要嵌套 IFNULL:IFNULL(a, IFNULL(b, c)) 写法又长又难读,改成 COALESCE(a, b, c) 一次取首个非 NULL 值,语义相同且跨库通用。
IFNULL 只处理 NULL,不处理空字符串:'' 与 ' ' 都会原样返回,清洗场景通常要先用 TRIM 再用 NULLIF 把空值统一成 NULL,最后才做兜底。