问题描述
任何人都可以帮助我理解为什么 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,'YYYYMMDD')) b,NVL(CASE WHEN '' = '' THEN NULL ELSE NULL END,'YYYYMMDD')) c,NVL(NULL,'YYYYMMDD')) d from dual;
我的实际查询使用 Trunc(NVL(:NEW_FORM_TIME_END,'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
解决方法
您的 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,NVL(CASE WHEN '' IS NOT NULL THEN NULL END,NVL(CASE WHEN '' = '' THEN NULL END,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 |
,
让我们分析所有这些:
NVL(CASE WHEN '' IS NULL THEN NULL ELSE NULL END,'YYYYMMDD'))
这应该返回 TO_DATE('19010101','YYYYMMDD'))
,因为 ''
与 Oracle 中的 NULL
相同,并且返回 THEN NULL
分支。
NVL(CASE WHEN '' IS NOT NULL THEN NULL ELSE NULL END,'YYYYMMDD'))
这个也应该返回 TO_DATE('19010101','YYYYMMDD')) since
'' IS NOT NULLis
false and the
ELSE NULL` 分支被返回。
NVL(CASE WHEN '' = '' THEN NULL ELSE NULL END,'YYYYMMDD'))
在 Oracle 中,'' = ''
转换为 NULL = NULL
,在 SQL 中计算为 NULL
,因此返回 `TO_DATE('19010101','YYYYMMDD'))。
NVL(NULL,'YYYYMMDD'))
这个也应该返回TO_DATE('19010101','YYYYMMDD'))