【问题标题】:Is there better Oracle operator to do null-safe equality check?是否有更好的 Oracle 运算符来进行空安全相等检查?
【发布时间】:2012-11-16 06:51:59
【问题描述】:

根据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 并且 where 应用于多个列。有没有更好的选择?

【问题讨论】:

标签: sql oracle plsql


【解决方案1】:

好吧,我不确定这是否更好,但使用LNNVL 可能会更简洁,这是一个函数(您只能在WHERE 子句中使用)如果给定表达式是 FALSE 或 UNKNOWN (NULL),则返回 TRUE。比如……

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 的行之外的所有行。

【讨论】:

    【解决方案2】:

    作为替代方案,您可以使用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
    

    【讨论】:

    • 此模式仅在您可以找到源数据中未使用的值(本例中为 -1)时才有效。如果 -1 是源数据的一部分,则比较可能会返回错误的结果。
    【解决方案3】:

    使用LNNVL 函数,当col1 和col2(答案中的x 和y)都为空时,您仍然会遇到问题。使用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')

    【讨论】:

    • 感谢您美化我的帖子!
    猜你喜欢
    • 1970-01-01
    • 2018-08-09
    • 2015-08-26
    • 2014-03-10
    • 1970-01-01
    • 1970-01-01
    • 2011-09-30
    • 1970-01-01
    相关资源
    最近更新 更多