使用/不使用 CASE 语句时,Oracle NVL 返回不一致结果

问题描述

任何人都可以帮助我理解为什么 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;

run results

我的实际查询使用 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 NULLisfalse and theELSE 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'))

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...