COALESCE 是什么
COALESCE 按顺序返回第一个非 NULL 的参数,是处理空值最通用的工具:做默认值、多字段兜底、把 NULL 换成业务默认值都靠它。它是 SQL 标准函数,MySQL、PostgreSQL、SQL Server、Oracle 都支持。与 MySQL 专有的 IFNULL 相比,COALESCE 可以接受任意多个参数;与 PostgreSQL 的 NULLIF 方向正好相反,后者是「相等就返回 NULL」。兜底后结果的数据类型由参数列表中优先级最高的类型决定,混用数字与字符串时要留意。
基本信息
| 作用 | 按顺序返回首个非 NULL 参数,全部为 NULL 时返回 NULL |
|---|---|
| 参数个数 | 任意多个;MySQL 的 IFNULL 只能写两个 |
| 返回类型 | 由参数列表中类型优先级最高的那个决定 |
| 平台差异 | MySQL 另有 IFNULL,PostgreSQL 另有 NULLIF(语义相反) |
| 与 CASE 的关系 | 等价于逐级判断的 CASE WHEN … IS NOT NULL THEN … |
| 适用平台 | 标准 SQL,MySQL 8.0 与 PostgreSQL 均支持 |
典型使用场景
- 给可空列设默认值:COALESCE(nickname, name, '匿名')
- 展示兜底:接口把 NULL 换成空串或占位文案,避免前端处理空值
- 多字段取第一个有值的:手机号缺失时用备用联系方式
- 拼接前兜底:COALESCE(CONCAT(a, b), '')
- 统计兜底:COALESCE(SUM(amount), 0) 让无数据时返回 0
- 计算兜底:把可能为 NULL 的列先补默认值再参与算术,防止整列变 NULL
示例
示例
SELECT COALESCE(nickname, name, '匿名') AS display_name, # 逐级兜底
COALESCE(phone, backup_phone, '') AS contact, # 取第一个有值的
COALESCE(SUM(o.amount), 0) AS total # 无数据时给 0
FROM users AS u
LEFT JOIN orders AS o ON o.user_id = u.id
GROUP BY u.id;
-- 拼接前兜底,避免 MySQL 的 CONCAT 遇 NULL 后整体变 NULL
SELECT CONCAT('name: ', COALESCE(nickname, '')) FROM users;空值处理函数对照
| 函数 | 作用 | 平台与注意 |
|---|---|---|
| COALESCE(a, b, …) | 返回首个非 NULL 参数 | 标准 SQL,通用 |
| IFNULL(a, b) | a 为 NULL 时返回 b | MySQL 专有,只能两个参数 |
| NULLIF(a, b) | a 与 b 相等时返回 NULL | 标准 SQL,与兜底方向相反 |
| ISNULL(a) | 判断是否为 NULL | MySQL 返回 0 或 1,SQL Server 语义不同 |
| IF(a, b, c) | 条件表达式 | MySQL 专有,PostgreSQL 用 CASE WHEN |
COALESCE 的返回类型由参数里优先级最高的类型决定:COALESCE(int_col, '0') 在 PostgreSQL 里会因为类型推断报错,混用类型时显式转换更稳。
对聚合结果兜底是常见写法:SUM、AVG、MIN、MAX 在无匹配行时返回 NULL,直接展示会出现空值,套一层 COALESCE 更符合报表预期。
兜底会掩盖数据缺失:把 NULL 一律换成 0 或空串后,缺失与真实为 0 无法区分,做数据质量统计时要保留原始判断。
判断「两个列是否相同」时用 COALESCE 先统一空值再比较,比 IS DISTINCT FROM 更易读,但在大表上会让列索引失效。
实践要点
- 参数按优先级排列:最可能为空的放前面,最不容易为空的放最后
- 兜底值要与业务一致:字符串用空串、数值用 0、金额用 0.00,避免类型混用
- 拼接与算术前先兜底,能一次性消除整列变 NULL 的问题
- 接口层兜底与数据库层兜底选一个,两层都写会让默认值来源难以追踪
- 统计场景优先 COALESCE(SUM(x), 0),而不是在应用层判断空值
- 跨库迁移时留意 IFNULL、NVL 这类专有函数的替换
常见误用
- 把 COALESCE 写在 WHERE 的条件列外侧,导致该列索引失效、退化为全表扫描
- 兜底值选成了业务上有意义的值(如 0),真实值与默认值从此无法区分
- 忘记聚合函数在无数据时返回 NULL,报表直接显示空白
- 多层兜底的参数顺序写反,取到了优先级更低的字段值
- 拼接文本前不做兜底,一行 NULL 就让整列结果变成空
- 跨库迁移时把 MySQL 的 IFNULL 直接搬过去,目标库不认这个函数
COALESCE 与 CASE 可以互相改写:单纯做空值兜底用 COALESCE 更短,需要先比较再取值这类复杂判断时才用 CASE。
兜底值尽量选业务上不可能出现的占位,例如字符串用空串、数值用 NULL 友好的默认值;把真实值可能取到的数字当兜底,会让两件事无法区分。