Is there better Oracle operator to do null-safe equality check?

前端 未结 3 1749
醉梦人生
醉梦人生 2020-12-19 23:34

According to this question, the way to perform an equality check in Oracle, and I want null to be considered equal null is something like

SELECT  COUNT(1)
           


        
相关标签:
3条回答
  • 2020-12-20 00:15

    Well, I'm not sure if this is better, but it might be slightly more concise to use LNNVL, a function (that you can only use in a WHERE clause) which returns TRUE if a given expression is FALSE or UNKNOWN (NULL). For example...

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

    ...will return all but the row where X = 1 and Y = 2.

    0 讨论(0)
  • 2020-12-20 00:28

    As an alternative you can use NVL function and designated literal which will be returned if a value is 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
    

    As @Codo has noted in the comment, of course, above approach requires choosing a literal comparing columns will never have. If comparing columns are of number datatype(for example) and are able to accept any value, then choosing -1 of course won't be an option. To eliminate that restriction we can use decode function(for numeric or character datatypes) for that:

     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
    
    0 讨论(0)
  • 2020-12-20 00:31

    With the LNNVL function, you still have a problem when col1 and col2 (x and y in the answer) are both null. With nvl it works but it is inefficient (not understood by the optimizer) and you have to find a value that cannot appear in the data (and the optimizer should know it cannot).
    For strings you can choose a value that have more characters than the maximum of the columns but it is dirty.

    The true efficient way to do it is to use the (undocumented) function SYS_OP_MAP_NONNULL().

    like this:

    where SYS_OP_MAP_NONNULL(col1) <> SYS_OP_MAP_NONNULL(col2)
    

    SYS_OP_MAP_NONNULL(a) is equivalent to nvl(a,'some internal value that cannot appear in the data but that is not null')

    0 讨论(0)
提交回复
热议问题