【问题标题】:Oracle NVL returning inconsistence result when used with/without CASE statement使用/不使用 CASE 语句时,Oracle NVL 返回不一致的结果
【发布时间】:2023-03-22 01:13:01
【问题描述】:

谁能帮我理解为什么 oracle db 在使用/不使用 CASE 语句时返回不一致的结果。

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;

我的实际查询使用TRUNC(NVL(:NEW_FORM_TIME_END, TO_DATE('19010101', 'YYYYMMDD'))) >= TRUNC(SYSDATE - INTERVAL '2' DAY),其中NEW_FORM_TIME_END 可能是空字符串或NULL,但我收到此错误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

【问题讨论】:

    标签: php oracle case oracle18c nvl


    【解决方案1】:

    您的 case 表达式是 VARCHAR2 类型,如果您不提供显式类型,这是默认类型。 NULL 文字没有类型。 NVL(<varchar2>, <date>)<date> 参数应用隐式类型转换。在其他 RDBMS 中,您只会因为不兼容的类型而得到错误。您的表达式的 PL/SQL 版本可能也会遇到类似的问题,尽管与您在查询中呈现的问题不完全相同。

    只要确保你总是比较相同的类型。

    试试这个来检查:

    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;
    

    或者,从您的表中创建一个视图,然后检查字典:

    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;
    

    产量

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

    【讨论】:

    • 谢谢:) 我不知道隐式类型转换
    【解决方案2】:

    我们来分析一下:

    NVL(CASE WHEN '' IS NULL THEN NULL ELSE NULL END ,TO_DATE('19010101', 'YYYYMMDD'))
    

    这应该返回TO_DATE('19010101', 'YYYYMMDD')),因为'' 与Oracle 中的NULL 相同,并且返回了THEN NULL 分支。

    NVL(CASE WHEN '' IS NOT NULL THEN NULL ELSE NULL END ,TO_DATE('19010101', 'YYYYMMDD'))
    

    这个也应该返回TO_DATE('19010101', 'YYYYMMDD')) since '' IS NOT NULLisfalse and theELSE NULL`分支返回。

    NVL(CASE WHEN '' = '' THEN NULL ELSE NULL END ,TO_DATE('19010101', 'YYYYMMDD'))
    

    在 Oracle 中,'' = '' 转换为 NULL = NULL,在 SQL 中,计算结果为 NULL,因此返回 `TO_DATE('19010101', 'YYYYMMDD'))。

    NVL(NULL ,TO_DATE('19010101', 'YYYYMMDD'))
    

    这个也应该返回TO_DATE('19010101', 'YYYYMMDD'))

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-11-19
      • 2011-05-25
      • 2017-09-17
      • 2021-04-01
      • 2012-12-22
      • 1970-01-01
      • 2021-02-09
      • 2020-12-29
      相关资源
      最近更新 更多