带有比较运算符的 SQL DECODE 函数

use*_*533 1 sql oracle

有人可以帮我理解下面的 SQL 输出吗?

SELECT * 
FROM dual 
WHERE SYSDATE >= DECODE(NVL(1,0),0,NULL,SYSDATE);
-- This returns row

SELECT * 
FROM dual 
WHERE SYSDATE <= DECODE(NVL(1,0),0,NULL,SYSDATE); 
-- No output if we use <= 

SELECT * 
FROM dual 
WHERE SYSDATE <= DECODE(NVL(1,0),0,SYSDATE,SYSDATE);
-- This returns row
Run Code Online (Sandbox Code Playgroud)

Jus*_*ave 5

问题在于decode返回的数据类型。这是基于第一个可选返回的数据类型,但默认为varchar2. 所以表达式(我替换nvl(1,0)1因为它不会改变行为并简化表达式)

DECODE(1,0,NULL,SYSDATE)
Run Code Online (Sandbox Code Playgroud)

返回一个varchar2值。这意味着查询实际上变成了

select *
  from dual
 where sysdate <= to_char(sysdate);
Run Code Online (Sandbox Code Playgroud)

如果你看一下计划你就可以看到

explain plan for
SELECT 1 FROM dual WHERE SYSDATE <= DECODE(1,0,null,SYSDATE); 

select * from table( dbms_xplan.display() );

PLAN_TABLE_OUTPUT
Plan hash value: 4034615273
 
-----------------------------------------------------------------
| Id  | Operation        | Name | Rows  | Cost (%CPU)| Time     |
-----------------------------------------------------------------
|   0 | SELECT STATEMENT |      |     1 |     2   (0)| 00:00:01 |
|*  1 |  FILTER          |      |       |            |          |
|   2 |   FAST DUAL      |      |     1 |     2   (0)| 00:00:01 |
-----------------------------------------------------------------
 
Predicate Information (identified by operation id):
---------------------------------------------------
 
   1 - filter(SYSDATE@!<=TO_CHAR(SYSDATE@!))
Run Code Online (Sandbox Code Playgroud)

如果将您设置nls_date_format为包含日期时间部分的内容,则查询将返回一行,因为现在隐式转换不会丢失时间信息。

alter session set nls_date_format = 'yyyy-mm-dd hh24:mi:ss';

SELECT 1 "null" FROM dual WHERE SYSDATE <= DECODE(1,0,null,SYSDATE); 

null
1
Run Code Online (Sandbox Code Playgroud)

或者,您可以decode通过显式强制转换返回正确的数据类型

SELECT 1 "cast(null)" 
  FROM dual 
 WHERE SYSDATE <= DECODE(1,0,cast(null as date),SYSDATE); 
Run Code Online (Sandbox Code Playgroud)

无论会话是什么,这都会返回一行,nls_date_format因为decode现在将返回一个date数据类型,并且您正在将 adate与 a进行比较date。这也是decode(1,0,sysdate,sysdate)起作用的原因——因为该decode表达式也返回一个date.