phporacle-databasecaseoracle18cnvl

Oracle NVL returning inconsistence result when used with/without CASE statement


Can anybody help me to understand why oracle db is returning inconsistence result when used with/without CASE statement.

SELECT NVL(CASE WHEN '' IS NULL THEN NULL ELSE NULL END ,TO_DATE('19010101', 'YYYYMMDD')) a,
   NVL(CASE WHEN '' IS NOT NULL THEN NULL ELSE NULL END ,TO_DATE('19010101', 'YYYYMMDD')) b,
   NVL(CASE WHEN '' = '' THEN NULL ELSE NULL END ,TO_DATE('19010101', 'YYYYMMDD')) c,
   NVL(NULL ,TO_DATE('19010101', 'YYYYMMDD')) d from dual;

run results

My actual query uses TRUNC(NVL(:NEW_FORM_TIME_END, TO_DATE('19010101', 'YYYYMMDD'))) >= TRUNC(SYSDATE - INTERVAL '2' DAY) where NEW_FORM_TIME_END could be empty string or NULL but I'm getting this error ORA-06550: line 240, column 91: PLS-00306: wrong number or types of arguments in call to '>=' ORA-06550: line 229, column 9: PL/SQL: Statement ignored


Solution

  • Your case expressions are of type VARCHAR2 which is the default type if you're not providing explicit types. A NULL literal doesn't have a type. NVL(<varchar2>, <date>) applies an implicit type conversion on the <date> argument. In other RDBMS, you'd simply get an error because of incompatible types. The PL/SQL version of your expression probably also suffers from a similar problem, although not exactly the same one as you're presenting in your query.

    Just make sure you always compare the same types.

    Try this to check:

    SELECT 
      NVL(CAST(CASE WHEN '' IS NULL THEN NULL END AS DATE), DATE '1901-01-01') a,
      NVL(CAST(CASE WHEN '' IS NOT NULL THEN NULL END AS DATE), DATE '1901-01-01') b,
      NVL(CAST(CASE WHEN '' = '' THEN NULL END AS DATE), DATE '1901-01-01') c,
      NVL(NULL, DATE '1901-01-01') d
    FROM dual;
    

    Or alternatively, create a view from your table and then check the dictionary:

    CREATE VIEW v AS
    SELECT 
      NVL(CASE WHEN '' IS NULL THEN NULL END, DATE '1901-01-01') a,
      NVL(CASE WHEN '' IS NOT NULL THEN NULL END, DATE '1901-01-01') b,
      NVL(CASE WHEN '' = '' THEN NULL END, DATE '1901-01-01') c,
      NVL(NULL, TO_DATE('19010101', 'YYYYMMDD')) d
    FROM dual;
    
    SELECT column_name, data_type
    FROM all_tab_cols
    WHERE table_name = 'V'
    ORDER BY column_name;
    

    Yielding

    |COLUMN_NAME|DATA_TYPE|
    |-----------|---------|
    |A          |VARCHAR2 |
    |B          |VARCHAR2 |
    |C          |VARCHAR2 |
    |D          |DATE     |