应优先用COALESCE而非NVL,因其符合SQL标准、支持多参数及跨数据库兼容;NVL仅限Oracle且仅支持两参数,类型要求更严格。
空值判断总报错?别用 IS NULL 做业务计算
直接在 where 或 select 中写 column = null 永远不成立,这是 sql 标准行为,不是数据库 bug。业务逻辑里真正要的是“把空换成默认值再参与运算”,不是“查出哪些是空”。nvl 和 coalesce 就是干这个的,但它们行为不同、兼容性也差。
-
NVL是 Oracle 专属函数,只接受两个参数:NVL(expr1, expr2)—— expr1 为NULL时返回 expr2,否则返回 expr1 -
COALESCE是 SQL 标准函数,支持多参数:COALESCE(expr1, expr2, expr3, ...),从左到右返回第一个非NULL的值 - Oracle 支持两者;PostgreSQL、MySQL 8.0+、SQL Server 只认
COALESCE;MySQL 5.7 及更早版本连COALESCE都不支持(得用IFNULL)
用 NVL 还是 COALESCE?看数据库和需求复杂度
如果只在 Oracle 上跑,且只需 fallback 一次(比如价格为空就用 0),NVL 更简洁;但只要涉及跨库迁移、或需要链式 fallback(比如先试 discount_price,没有再试 list_price,最后才用 0),必须用 COALESCE。
-
NVL('abc', 'def')→'abc';NVL(NULL, 'def')→'def' -
COALESCE(NULL, 'a', 'b')→'a';COALESCE(NULL, NULL, 'c')→'c' -
COALESCE所有参数必须类型兼容,数据库会尝试隐式转换;NVL要求两个参数类型严格一致,否则报错ORA-00932: inconsistent datatypes
常见错误:把 COALESCE 当成条件分支写
COALESCE 不是 CASE WHEN,它不做逻辑判断,只做空值跳过。很多人想表达“如果 A 为空且 B > 100,则用 C”,结果错写成 COALESCE(A, B > 100, C) —— 这会直接报错,因为 B > 100 是布尔表达式,不是可返回的值。
- 正确写法只能是:
COALESCE(A, CASE WHEN B > 100 THEN C END) - 或者更清晰:
CASE WHEN A IS NOT NULL THEN A WHEN B > 100 THEN C ELSE D END - 另一个坑:
COALESCE(col, '')在某些场景下会让索引失效(尤其 col 是数字型,而 '' 被转成 0),不如显式 cast:COALESCE(col::text, '')(PostgreSQL)或COALESCE(CAST(col AS VARCHAR), '')
性能差异真有那么大?多数时候可以忽略
单次调用 NVL 或 COALESCE 几乎没有可观测性能差别。真正影响性能的是嵌套层数和参数表达式的开销——比如 COALESCE(func1(), func2(), func3()) 会依次执行直到第一个非空,如果 func1() 很慢,后面根本不会执行;但如果 func1() 总是返回 NULL,那就每次都得跑满三个函数。
- 避免在
COALESCE里放子查询或复杂函数,尤其是出现在 WHERE 条件中时 - Oracle 中
NVL对索引列使用可能阻止索引范围扫描(如WHERE NVL(status, 'A') = 'A'),改用status = 'A' OR status IS NULL更稳妥 - 如果字段本身允许空且高频参与计算,考虑建函数索引:
CREATE INDEX idx_nvl_status ON t(NVL(status, 'A'))(Oracle)









