根据这个问题,在 Oracle 中执行相等检查的方式,我希望 null 被视为等于 null 类似于
SELECT COUNT(1)
FROM TableA
WHERE
wrap_up_cd = val
AND ((brn_brand_id = filter) OR (brn_brand_id IS NULL AND filter IS NULL))
这真的会让我的代码变脏,特别是如果我有很多这样的 where 并且 where 应用于多个列。有没有更好的选择呢?
好吧,我不确定这是否更好LNNVL,但使用函数(只能在WHERE子句中使用)可能会更简洁一些,TRUE如果给定表达式是FALSE或 UNKNOWN ( NULL) 则返回。例如...
WITH T AS
(
SELECT 1 AS X, 1 AS Y FROM DUAL UNION ALL
SELECT 1 AS X, 2 AS Y FROM DUAL UNION ALL
SELECT 1 AS X, NULL AS Y FROM DUAL UNION ALL
SELECT NULL AS X, 1 AS Y FROM DUAL
)
SELECT
*
FROM
T
WHERE
LNNVL(X <> Y);
...将返回除 X = 1 和 Y = 2 的行之外的所有行。
使用该函数,当和(和在答案中) 都为空LNNVL时,您仍然会遇到问题。它可以工作,但效率低下(优化器不理解),您必须找到一个不能出现在数据中的值(优化器应该知道它不能)。
对于字符串,您可以选择一个字符数超过列的最大值但它很脏的值。col1col2xynvl
真正有效的方法是使用(未记录的)函数SYS_OP_MAP_NONNULL()。
像这样:
where SYS_OP_MAP_NONNULL(col1) <> SYS_OP_MAP_NONNULL(col2)
SYS_OP_MAP_NONNULL(a)相当于nvl(a,'some internal value that cannot appear in the data but that is not null')
作为替代方案,您可以使用NVL函数和指定文字,如果值为空,则将返回:
-- both are not nulls
SQL> with t1(col1, col2) as(
2 select 123, 123 from dual
3 )
4 select 1 res
5 from t1
6 where nvl(col1, -1) = nvl(col2, -1)
7 ;
RES
----------
1
-- one of the values is null
SQL> with t1(col1, col2) as(
2 select null, 123 from dual
3 )
4 select 1 res
5 from t1
6 where nvl(col1, -1) = nvl(col2, -1)
7 ;
no rows selected
-- both values are nulls
SQL> with t1(col1, col2) as(
2 select null, null from dual
3 )
4 select 1 res
5 from t1
6 where nvl(col1, -1) = nvl(col2, -1)
7 ;
RES
----------
1
正如@Codo 在评论中指出的那样,当然,上述方法需要选择一个永远不会有的文字比较列。如果比较列是数字数据类型(例如)并且能够接受任何值,那么选择 -1 当然不是一个选项。为了消除这种限制,我们可以使用decode函数(用于数字或字符数据类型):
with t1(col1, col2) as(
2 select null, null from dual
3 )
4 select 1 res
5 from t1
6 where decode(col1, col2, 'same', 'different') = 'same'
7 ;
RES
----------
1