equal_null:NULL 安全的等值比较
速查结论
equal_null(expr1, expr2) 是 Spark SQL 中用于NULL 安全等值比较的函数。与普通 = 运算符不同,当两个操作数都为 NULL 时返回 true,只有一个为 NULL 时返回 false,都不为 NULL 时行为与 = 一致。简单来说:equal_null 永远返回 true 或 false,不会返回 NULL。
语法
equal_null(expr1, expr2)
参数说明
| 参数 | 说明 |
|---|---|
expr1 | 待比较的第一个表达式 |
expr2 | 待比较的第二个表达式 |
返回值:
- 两个操作数都为 NULL → true
- 只有一个操作数为 NULL → false
- 都不为 NULL → 与
=结果一致
类型要求:两个表达式必须是相同类型或可以强制转换为共同类型,必须是可用于等值比较的类型。不支持 Map 类型。对于复杂类型(数组/结构体),字段的数据类型必须是可排序的。
Since: 3.4.0
示例
基础比较
-- 都不为 NULL:行为与 = 一致
SELECT equal_null(3, 3);
-- 结果: true
SELECT equal_null(3, 5);
-- 结果: false
NULL 安全比较
-- 两个都为 NULL:返回 true(区别于 = 返回 NULL)
SELECT equal_null(NULL, NULL);
-- 结果: true
-- 只有一个为 NULL:返回 false(区别于 = 返回 NULL)
SELECT equal_null(true, NULL);
-- 结果: false
SELECT equal_null(NULL, 'abc');
-- 结果: false
类型不匹配
-- 类型不同且无法隐式转换:返回 false
SELECT equal_null(1, '11');
-- 结果: false
equal_null vs = 运算符行为对比
这是理解 equal_null 的关键——三个场景的对比:
| 场景 | A = B | equal_null(A, B) |
|---|---|---|
| 都不为 NULL,值相等 | true | true |
| 都不为 NULL,值不等 | false | false |
| 都为 NULL | NULL | true |
| 一个为 NULL | NULL | false |
-- 直观对比表
WITH test AS (
SELECT 1 AS a, 1 AS b UNION ALL
SELECT 1, 2 UNION ALL
SELECT NULL, NULL UNION ALL
SELECT 1, NULL
)
SELECT
a,
b,
a = b AS equal_operator,
equal_null(a, b) AS equal_null_func
FROM test;
-- 结果:
-- a b equal_operator equal_null_func
-- 1 1 true true
-- 1 2 false false
-- NULL NULL NULL true -- 区别在这里
-- 1 NULL NULL false -- 区别在这里
equal_null vs IS DISTINCT FROM 对比
| 函数 | 都为 NULL | 一个为 NULL | 返回值特征 |
|---|---|---|---|
equal_null(A, B) | true | false | 比较"是否相等",永远返回 true/false |
A IS NOT DISTINCT FROM B | true | false | 与 equal_null 逻辑一致,NULL 视为相等 |
A IS DISTINCT FROM B | false | true | 与 IS NOT DISTINCT FROM 取反 |
-- equal_null 与 IS NOT DISTINCT FROM 语义等价
SELECT equal_null(NULL, NULL);
-- 结果: true
SELECT NULL IS NOT DISTINCT FROM NULL;
-- 结果: true
-- IS DISTINCT FROM 是取反
SELECT NULL IS DISTINCT FROM NULL;
-- 结果: false
选型建议:
- 需要 NULL 安全比较且永远返回 true/false:用
equal_null - 偏好 ANSI SQL 标准语法:用
IS NOT DISTINCT FROM - 需要找出"不同"的行(含 NULL 比较):用
IS DISTINCT FROM
常见报错与避坑指南
Map 类型不支持
equal_null 不支持 Map 类型的比较,传入 Map 类型会报错。
-- 错误写法:Map 类型不支持
SELECT equal_null(map('a', 1), map('a', 1));
-- AnalysisException: cannot resolve 'equal_null(map('a', 1), map('a', 1))'
-- equal_null does not support map type
-- 替代方案:先将 Map 转为 JSON 字符串再比较
SELECT equal_null(to_json(map('a', 1)), to_json(map('a', 1)));
复杂类型的字段必须可排序
对于包含嵌套字段的复杂类型(如 struct),字段数据类型必须支持排序,否则可能报错。
-- 错误写法:struct 中包含不可排序的字段类型
SELECT equal_null(
named_struct('name', 'a', 'data', map('k', 'v')),
named_struct('name', 'a', 'data', map('k', 'v'))
);
-- 可能报错:data type mismatch
-- 正确写法:确保复杂类型的字段是可排序的基本类型
SELECT equal_null(
named_struct('name', 'a', 'value', 1),
named_struct('name', 'a', 'value', 1)
);
-- 结果: true
与普通 = 运算符的 NULL 传播陷阱
在 WHERE 条件中,= 遇到 NULL 会直接排除该行,而 equal_null 会返回 false(而非 NULL),这可能导致不同的过滤结果。
-- 数据准备
WITH test AS (
SELECT 1 AS id, 'A' AS tag UNION ALL
SELECT 2 AS id, NULL AS tag UNION ALL
SELECT 3 AS id, 'A' AS tag
)
-- = 运算符:NULL 行被排除(因为 NULL = 'A' 结果为 NULL,被视为 false)
SELECT * FROM test WHERE tag = 'A';
-- 结果: id=1, id=3
-- equal_null:明确返回 false,同样排除 NULL 行,但语义更清晰
SELECT * FROM test WHERE equal_null(tag, 'A');
-- 结果: id=1, id=3(与上面相同,但不会产生 =NULL 的语义歧义)
在过滤场景中,如果只是想筛选特定值,使用
=是安全的(NULL 行自然被排除)。equal_null 的优势在 JOIN 条件和需要明确判断"两个值是否相等(包括 NULL)"的场景中。
📱关注公众号
「数据仓库技术」文章同步更新,不错过每一篇干货

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