NULLIF 是什么
NULLIF(a, b) 在两个参数相等时返回 NULL,否则返回第一个参数。它有两个高频用途:给除法加保护,把分母为 0 的情况变成 NULL 而不是报错;把 N/A、- 这类哨兵值统一清洗成 NULL,让后面的聚合口径一致。
基本信息
| 规则 | a 等于 b 时返回 NULL,否则返回 a |
|---|---|
| 等价写法 | CASE WHEN a = b THEN NULL ELSE a END |
| 参数顺序 | 第一个参数是“被保留的值”,写反后语义完全改变 |
| 除零保护 | 总价 / NULLIF(数量, 0):分母为 0 时整体结果为 NULL |
| 哨兵值清洗 | NULLIF(status, 'N/A') 把占位值变成 NULL |
| 类型协商 | 两库比较前都会做类型协商,两侧类型尽量保持一致 |
两种典型用法
两种典型用法
-- 防止除零:分母为 0 时结果为 NULL,不会让语句失败
SELECT total / NULLIF(qty, 0) AS unit_price FROM orders;
-- 哨兵值清洗:把 'N/A' 统一成 NULL
SELECT NULLIF(status, 'N/A') AS status_clean FROM t;
-- 清洗后再兜底展示,读数据与展示口径分开
SELECT COALESCE(NULLIF(status, 'N/A'), '未知') AS status_show FROM t;等价改写
等价改写
-- 与 NULLIF 等价的 CASE 写法,便于在不支持该函数的场景移植
SELECT CASE WHEN qty = 0 THEN NULL ELSE qty END AS qty_safe FROM orders;
-- 注意:这里的判断式是 qty = 0,与 NULLIF(qty, 0) 的“相等即转空”语义一致
-- 分母为 0 时 CASE 同样返回 NULL,防除零效果相同,但代码更长两库除零行为
| 表达式 | MySQL 8 | PostgreSQL |
|---|---|---|
| x / 0 | 返回 NULL 并产生告警 | 报错 division by zero |
| x / NULLIF(0, 0) | NULL | NULL |
| NULLIF(0, 0) | NULL | NULL |
| NULLIF('a','a') | NULL | NULL |
| NULLIF(NULL, 1) | NULL | NULL |
典型使用场景
- 算客单价、转化率、占比时保护分母
- 清洗导入数据里的哨兵值:N/A、无、-、0 统一成 NULL
- 对比两列差异时把相同值转成 NULL,方便筛出不一致的行
- 给唯一索引腾位置:把不参与唯一性约束的占位值转成 NULL
- 配合 COALESCE 做展示层兜底,区分“无值”与“未知”
- 做空值率统计之前统一口径,避免把占位值算进有效数据
- 把 Excel、CSV 导入的占位值先归一化成 NULL,再做后续聚合
NULLIF 与 COALESCE 常成对出现:NULLIF 负责把无意义的值变成 NULL,COALESCE 负责给 NULL 补一个展示默认值。这样存储口径与展示口径就分开了,报表也更好解释。两者的参数都是按位置求值,注意顺序不要反。
两库都支持 NULLIF,属于 SQL 标准条件表达式:它比 CASE 更短,也比依赖各库的 IF 系列函数更可移植,写跨库 SQL 时优先选它。
MySQL 里除数为 0 只返回 NULL 并告警,PostgreSQL 直接抛 division by zero 让整条语句失败。跨库 SQL 不要省掉除零保护,NULLIF 是两库通用的写法。