跳到主要内容

nvl:NULL 值替换

速查结论

nvl(expr1, expr2) 是 Spark SQL 中用于将 NULL 替换为默认值的函数。当 expr1 为 NULL 时返回 expr2,否则返回 expr1。注意:nvl 只接受2个参数,如需多值回退请使用 coalesce(参数数量不限制),如需 ANSI SQL 标准语法请使用 ifnull(语义等价)。

语法

nvl(expr1, expr2)

参数说明

参数说明
expr1待检查的表达式
expr2当 expr1 为 NULL 时的替代值

返回值:如果 expr1NULL,则返回 expr2;否则返回 expr1。返回类型为 expr1expr2 的公共类型(common type)。

Since: 2.0.0

示例

基础用法 — NULL 替换为默认值

-- expr1 为 NULL,返回 expr2
SELECT nvl(NULL, array('2'));
-- 结果: ["2"]

-- expr1 不为 NULL,返回原值
SELECT nvl('hello', 'world');
-- 结果: hello

数值 NULL 替换为默认值

-- 将 NULL 销售额替换为 0
SELECT
product_id,
nvl(sales_amount, 0) AS sales_amount
FROM sales;

字符串 NULL 替换为默认占位符

-- 将 NULL 用户名替换为 'Unknown'
SELECT nvl(username, 'Unknown') AS username
FROM users;

嵌套使用 — 多层 NULL 回退

-- nvl 只有2个参数,但可以通过嵌套实现3级回退
SELECT nvl(col1, nvl(col2, 'default_value'))
FROM t;

嵌套3层以上时,建议改用 coalesce(col1, col2, col3, 'default_value'),可读性更好。

nvl vs nvl2 vs coalesce vs ifnull 对比

这些函数都与 NULL 处理相关,但适用场景不同:

函数参数个数返回逻辑适用场景
nvl(expr1, expr2)固定 2 个expr1 IS NULL → expr2简单 NULL 替换(Spark SQL 特有语法)
nvl2(expr1, expr2, expr3)固定 3 个expr1 IS NOT NULL → expr2,否则 → expr3NULL / 非 NULL 双分支取值
coalesce(expr1, ..., exprN)不限返回第一个非 NULL 值多级回退,多列优选
ifnull(expr1, expr2)固定 2 个等同于 nvlANSI SQL 标准语法,跨引擎迁移首选
-- nvl: expr1 为 NULL 时返回默认值
SELECT nvl(col, 0) FROM t;

-- nvl2: expr1 不为 NULL 时返回 expr2,否则返回 expr3
SELECT nvl2(col, '有值', '无值') FROM t;

-- coalesce: 多列中取第一个非 NULL 值
SELECT coalesce(mobile, phone, email, '无联系方式') AS contact
FROM users;

-- ifnull: 语义与 nvl 一致,ANSI SQL 标准
SELECT ifnull(col, 0) FROM t;

nvl 与 nvl2 的核心区别

nvlnvl2 虽然名字相似,但逻辑截然不同:

对比维度nvlnvl2
参数个数2 个3 个
判断逻辑expr1 IS NULL → 返回 expr2expr1 IS NOT NULL → 返回 expr2,否则 → 返回 expr3
使用场景"如果是 NULL,用默认值替代""如果是 NULL 怎么办,不是 NULL 又怎么办"
-- nvl: 只处理 NULL 的情况
SELECT nvl(status, 0) FROM orders;
-- status 为 NULL → 0,status 有值 → 原值

-- nvl2: 同时处理 NULL 和 非 NULL 两种情况
SELECT nvl2(status, '已处理', '未处理') FROM orders;
-- status 不为 NULL → '已处理',status 为 NULL → '未处理'

选型建议

  • 简单 NULL → 默认值:用 nvl,简洁直观
  • NULL / 非 NULL 两种路径取不同值:用 nvl2
  • 多个备选列取第一个非 NULL:用 coalesce
  • 跨平台 SQL 兼容(如从 Hive / MySQL 迁移):用 ifnullcoalesce

常见报错与避坑指南

参数类型不兼容导致报错

nvl(expr1, expr2) 要求两个参数的类型能够隐式转换为公共类型,否则会抛出 AnalysisException

-- 错误写法:STRING 和 INT 没有公共类型
SELECT nvl(name, 0) FROM users;
-- AnalysisException: cannot resolve 'nvl(name, 0)' due to data type mismatch

-- 正确写法:统一为同类型或可隐式转换的类型
SELECT nvl(name, '0') FROM users;

-- 也可以使用 CAST 显式转换
SELECT nvl(name, CAST(0 AS STRING)) FROM users;

nvl 不会短路求值

这是一个常见的性能陷阱:即使 expr1 不为 NULLexpr2 中的表达式也会被计算

-- 性能陷阱:expensive_udf() 总会执行
SELECT nvl(col, expensive_udf(col)) FROM t;
-- 即使 col 不为 NULL,expensive_udf 仍然会计算每一行
-- 避免非必要计算:用 CASE WHEN 实现短路
SELECT CASE WHEN col IS NULL THEN expensive_udf(col) ELSE col END
FROM t;

nvl 无法处理空字符串

nvl 只识别 NULL,不识别空字符串 ''

-- nvl 对空字符串无效
SELECT nvl('', 'default');
-- 结果: ''(空字符串,不是 'default')

-- 如需同时处理 NULL 和空字符串,用 CASE WHEN
SELECT CASE WHEN col IS NULL OR col = '' THEN 'default' ELSE col END
FROM t;
📱关注公众号

「数据仓库技术」文章同步更新,不错过每一篇干货

微信公众号二维码
💬加群交流

备注「数据仓库技术」加入社群,每日一道大厂SQL真题

交流微信二维码

你可能还想看