coalesce返回首个非NULL值,仅处理null不识别空字符串或0;nullif在两参数相等时返回null,用于主动制造null而非检测null;二者应先nullif清洗再coalesce兜底。

COALESCE 用来兜底 NULL,但别把它当 IF-ELSE 用
COALESCE 是 sql 标准函数,作用是返回参数列表中第一个非 NULL 的值。它不是条件分支工具,而是“取首个有效值”的快捷写法。
常见错误现象:有人用 COALESCE(a, b, c, 'default') 替代逻辑判断,结果发现 a 是空字符串或 0 时仍被选中——因为 COALESCE 只认 NULL,不识别业务意义上的“无效值”。
使用场景:
- 字段可能为
NULL,需要 fallback 到另一个字段(如COALESCE(phone_work, phone_home, '未提供')) - 多表关联后某侧字段缺失,需统一补默认值
注意点:
- 所有参数必须类型兼容,否则数据库可能报错或隐式转换(如 postgresql 会严格检查,mysql 可能转成字符串)
- 性能上无额外开销,但参数过多(比如 10+ 个)会影响可读性,建议拆到应用层或用
CASE
SELECT COALESCE(NULL, 'fallback1', 'fallback2'); -- 返回 'fallback1'
NULLIF 专治“想把某值变成 NULL”,不是 NULL 检测工具
NULLIF 接收两个参数,当它们相等时返回 NULL,否则返回第一个参数。它的核心用途是“主动制造 NULL”,而不是判断是否为 NULL。
常见错误现象:写成 NULLIF(col, NULL) —— 这永远返回 col,因为任何值与 NULL 比较都为 UNKNOWN,不会触发返回 NULL 的条件。
使用场景:
- 把空字符串转为
NULL:NULLIF(name, '') - 避免除零错误:
price / NULLIF(quantity, 0) - 清洗重复的默认值(如
NULLIF(status, 'unknown'))
注意点:
- 第二个参数不能是表达式结果为
NULL的情况(比如子查询返回NULL),否则行为不可控 - 在 WHERE 子句里慎用,可能破坏索引下推(如
WHERE NULLIF(x, 'N') IS NOT NULL通常比不上WHERE x != 'N' AND x IS NOT NULL)
SELECT NULLIF('hello', 'hello'); -- 返回 NULL
SELECT NULLIF('hello', 'world'); -- 返回 'hello'
COALESCE 和 NULLIF 组合用很常见,但顺序和嵌套容易翻车
两者常一起出现,典型模式是先用 NULLIF 把“伪有效值”清理成 NULL,再用 COALESCE 做兜底。但顺序错了就白干。
常见错误现象:
- 写成
COALESCE(NULLIF(col, ''), 'default')是对的;反过来NULLIF(COALESCE(col, ''), 'default')就毫无意义 - 嵌套过深导致逻辑难读,比如
COALESCE(NULLIF(TRIM(col), ''), NULLIF(other_col, 'N/A'), '—')
性能影响:
- 纯计算函数,无 I/O 开销,但每层调用都有轻微 CPU 成本
- 在大表聚合或窗口函数中高频使用时,建议提前在物化视图或应用层处理
要点:
- 先
NULLIF,再COALESCE,符合数据清洗流水线直觉 - 如果要处理多种“无效值”,优先用
CASE,比堆砌NULLIF更清晰 - 所有字符串操作(如
TRIM)应放在NULLIF之前,避免空格干扰判断
SELECT COALESCE(NULLIF(TRIM(description), ''), '[无描述]');
不同数据库对 NULLIF 和 COALESCE 的 NULL 处理一致,但类型推导有差异
标准 SQL 规定了行为,所以 COALESCE 和 NULLIF 在 PostgreSQL、SQL Server、sqlite、MySQL 8.0+ 上语义一致。真正容易出问题的是类型隐式转换。
常见坑:
- MySQL 5.7 对
COALESCE(1, 'abc')会转成字符串,而 PostgreSQL 直接报错 - SQL Server 中
NULLIF(datetime_col, '1900-01-01')若后者类型不匹配,可能触发意外转换 - SQLite 把一切当 TEXT 处理,
NULLIF(0, 0.0)返回NULL(数值相等),但NULLIF('0', 0)不等(类型不同)
建议做法:
- 显式转换类型,比如
COALESCE(CAST(a AS TEXT), CAST(b AS TEXT)) - 在跨库迁移或 ORM 生成 SQL 时,检查生成的参数类型是否被自动包装
- 单元测试里加类型断言,不只是值断言
SELECT COALESCE(CAST(age AS TEXT), '未知'); -- 比 COALESCE(age, '未知') 更稳
实际写的时候,最容易被忽略的是:你写的 NULLIF 是否真能把目标值判等——比如比较前没去空格、大小写不一致、时区导致时间字面量不匹配。这些不会报错,但结果不对。