sqloracle-databaseoracle9i

Greatest not null column


I need to update a row with a formula based on the largest value of two DATETIME columns. I would normally do this:

GREATEST(date_one, date_two)

However, both columns are allowed to be NULL. I need the greatest date even when the other is NULL (of course, I expect NULL when both are NULL) and GREATEST() returns NULL when one of the columns is NULL.

This seems to work:

GREATEST(COALESCE(date_one, date_two), COALESCE(date_two, date_one))

But I wonder... am I missing a more straightforward method?


Solution

  • COALESCE(GREATEST(date_one, date_two), date_one, date_two)

    EDIT Here's one possible n-column generalization in which the additional effort to add extra columns remains constant as the number of columns grows.

    First, a table with test data:

    create table MY_TABLE
                 ( MY_KEY number
                 , COL_1  number
                 , COL_2  number
                 , COL_3  number
                 , COL_4  number
                 , primary key ( MY_KEY )
                 )
    ;
    insert into MY_TABLE
    select  0, null, null, null, null from dual union all
    select  1, null, null, null,    5 from dual union all
    select  2, null, null,    7, null from dual union all
    select  3, null, null,    7,    5 from dual union all
    select  4, null,    2, null, null from dual union all
    select  5, null,    2, null,    5 from dual union all
    select  6, null,    2,    7, null from dual union all
    select  7, null,    2,    7,    5 from dual union all
    select  8,    4, null, null, null from dual union all
    select  9,    4, null, null,    5 from dual union all
    select 10,    4, null,    7, null from dual union all
    select 11,    4, null,    7,    5 from dual union all
    select 12,    4,    2, null, null from dual union all
    select 13,    4,    2, null,    5 from dual union all
    select 14,    4,    2,    7, null from dual union all
    select 15,    4,    2,    7,    5 from dual
    ;
    commit
    ;
    

    Then, a query:

    with coalesced_columns
      as (
           select MY_KEY
                , coalesce
                  ( aa.COL_1
                  , aa.COL_2
                  , aa.COL_3
                  , aa.COL_4
               -- , ... and so on, and so on, and so on
                  )
               as FIRST_NON_NULL
             from MY_TABLE
                  aa
         )
    select greatest
           ( nvl( aa.COL_1, zz.FIRST_NON_NULL )
           , nvl( aa.COL_2, zz.FIRST_NON_NULL )
           , nvl( aa.COL_3, zz.FIRST_NON_NULL )
           , nvl( aa.COL_4, zz.FIRST_NON_NULL )
        -- , ... and so on, and so on, and so on
           )
        as GREATEST_NON_NULL
         , zz.FIRST_NON_NULL -- from "with" clause
         , aa.COL_1
         , aa.COL_2
         , aa.COL_3
         , aa.COL_4
      from MY_TABLE
           aa
      join coalesced_columns
           zz
        on zz.MY_KEY = aa.MY_KEY
    ;
    

    As always, the proof is in the pudding:

    |-------------------+----------------+-------+-------+-------+-------|
    | GREATEST_NON_NULL | FIRST_NON_NULL | COL_1 | COL_2 | COL_3 | COL_4 |
    |-------------------+----------------+-------+-------+-------+-------|
    |                 - |              - |     - |     - |     - |     - |
    |                 5 |              5 |     - |     - |     - |     5 |
    |                 7 |              7 |     - |     - |     7 |     - |
    |                 7 |              7 |     - |     - |     7 |     5 |
    |                 2 |              2 |     - |     2 |     - |     - |
    |                 5 |              2 |     - |     2 |     - |     5 |
    |                 7 |              2 |     - |     2 |     7 |     - |
    |                 7 |              2 |     - |     2 |     7 |     5 |
    |                 4 |              4 |     4 |     - |     - |     - |
    |                 5 |              4 |     4 |     - |     - |     5 |
    |                 7 |              4 |     4 |     - |     7 |     - |
    |                 7 |              4 |     4 |     - |     7 |     5 |
    |                 4 |              4 |     4 |     2 |     - |     - |
    |                 5 |              4 |     4 |     2 |     - |     5 |
    |                 7 |              4 |     4 |     2 |     7 |     - |
    |                 7 |              4 |     4 |     2 |     7 |     5 |
    |-------------------+----------------+-------+-------+-------+-------|