Oracle NVL 在使用 with/without CASE 语句时返回不一致的结果
Oracle NVL returning inconsistence result when used with/without CASE statement
任何人都可以帮助我理解为什么 oracle db 在使用 with/without 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
让我们来分析一下:
NVL(CASE WHEN '' IS NULL THEN NULL ELSE NULL END ,TO_DATE('19010101', 'YYYYMMDD'))
这应该 return TO_DATE('19010101', 'YYYYMMDD'))
因为 ''
与 Oracle 中的 NULL
相同并且 THEN NULL
分支是 returned。
NVL(CASE WHEN '' IS NOT NULL THEN NULL ELSE NULL END ,TO_DATE('19010101', 'YYYYMMDD'))
这个也应该 return TO_DATE('19010101', 'YYYYMMDD')) since
'' IS NOT NULLis
false and the
ELSE NULL` branch is returned.
NVL(CASE WHEN '' = '' THEN NULL ELSE NULL END ,TO_DATE('19010101', 'YYYYMMDD'))
在 Oracle 中,'' = ''
转换为 NULL = NULL
,在 SQL 中计算为 NULL
,因此 `TO_DATE('19010101', 'YYYYMMDD')) 是 returned.
NVL(NULL ,TO_DATE('19010101', 'YYYYMMDD'))
这个也应该returnTO_DATE('19010101', 'YYYYMMDD'))
您的 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;
或者,从您的 table 创建一个视图,然后检查字典:
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 |
任何人都可以帮助我理解为什么 oracle db 在使用 with/without 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
让我们来分析一下:
NVL(CASE WHEN '' IS NULL THEN NULL ELSE NULL END ,TO_DATE('19010101', 'YYYYMMDD'))
这应该 return TO_DATE('19010101', 'YYYYMMDD'))
因为 ''
与 Oracle 中的 NULL
相同并且 THEN NULL
分支是 returned。
NVL(CASE WHEN '' IS NOT NULL THEN NULL ELSE NULL END ,TO_DATE('19010101', 'YYYYMMDD'))
这个也应该 return TO_DATE('19010101', 'YYYYMMDD')) since
'' IS NOT NULLis
false and the
ELSE NULL` branch is returned.
NVL(CASE WHEN '' = '' THEN NULL ELSE NULL END ,TO_DATE('19010101', 'YYYYMMDD'))
在 Oracle 中,'' = ''
转换为 NULL = NULL
,在 SQL 中计算为 NULL
,因此 `TO_DATE('19010101', 'YYYYMMDD')) 是 returned.
NVL(NULL ,TO_DATE('19010101', 'YYYYMMDD'))
这个也应该returnTO_DATE('19010101', 'YYYYMMDD'))
您的 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;
或者,从您的 table 创建一个视图,然后检查字典:
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 |