是否有更好的Oracle运算符进行空安全等式检查?

时间:2012-11-16 06:52:00

标签: sql oracle plsql

根据this question,在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应用于多个列。对此有更好的选择吗?

3 个答案:

答案 0 :(得分:5)

好吧,我不确定这是否更好,但使用LNNVL这个函数可能会稍微简洁一点(你只能在{{1}中使用如果给定表达式为WHERE或UNKNOWN(TRUE),则返回FALSE。例如......

NULL

...将返回除X = 1和Y = 2之外的所有行。

答案 1 :(得分:2)

作为替代方案,您可以使用NVL函数和指定的文字,如果值为null,将返回该文字:

-- 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

答案 2 :(得分:1)

使用LNNVL功能,当col1col2(答案中的xy)都为空时,您仍会遇到问题。使用nvl它可以工作,但效率很低(优化器不理解),你必须找到一个不能出现在数据中的值(优化器应该知道它不能)。
对于字符串,您可以选择一个字符数多于列的最大值但值很脏的值。

真正有效的方法是使用(未记录的)函数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')