简短的回答,不。
稍微长一点的答案是差不多。
似乎从每个语句获得的结果是相同的。如果我们使用DUMP函数来评估返回的数据类型,你会明白我的意思:
SQL> select dump(case 1 when 2 then null else 0 end) as simple_case
2 , dump(case when 1 = 2 then null else 0 end) as searched_case
3 , dump(decode(1, 2, null, 0)) as decode
4 from dual;
SIMPLE_CASE SEARCHED_CASE DECODE
------------------ ------------------ -----------------
Typ=2 Len=1: 128 Typ=2 Len=1: 128 Typ=1 Len=1: 48
SQL小提琴
您可以看到 DECODE 的数据类型是 1,而两个 CASE 语句“返回”数据类型为 2。使用 Oracle 的数据类型摘要,DECODE 返回一个 VARCHAR2(数据类型 1),而 CASE 语句“返回” " 数字(数据类型 2)。
我认为这是因为,顾名思义,DECODE 是一个函数,而 CASE 不是,这意味着它们在内部的实现方式不同。没有真正的方法可以证明这一点。
你可能认为这并没有真正影响任何事情。如果你需要它是一个数字,Oracle会在隐式转换规则下将字符隐式转换为数字,对吗?这也不是真的,它不会在 UNION 中工作,因为数据类型必须相同;Oracle 不会进行任何隐式转换以方便您。其次,这是 Oracle 关于隐式转换的说法:
Oracle 建议您指定显式转换,而不是依赖隐式或自动转换,原因如下:
使用显式数据类型转换函数时,SQL 语句更容易理解。
隐式数据类型转换会对性能产生负面影响,尤其是在将列值的数据类型转换为常量而不是相反时。
隐式转换取决于它发生的上下文,并且可能不会在每种情况下都以相同的方式工作。例如,从日期时间值到 VARCHAR2 值的隐式转换可能会返回意外年份,具体取决于 NLS_DATE_FORMAT 参数的值。
隐式转换的算法可能会随着软件版本和 Oracle 产品的变化而变化。显式转换的行为更可预测。
这不是一个漂亮的清单。但倒数第二点让我很好地了解了约会。如果我们采用上一个查询并将其转换为使用日期的查询:
select case sysdate when trunc(sysdate) then null
else sysdate
end as simple_case
, case when sysdate = trunc(sysdate) then null
else sysdate
end as searched_case
, decode(sysdate, trunc(sysdate), null, sysdate) as decode
from dual;
再一次,在这个查询中使用 DUMP,CASE 语句返回数据类型 12,一个 DATE。DECODE 已转换sysdate
为 VARCHAR2。
SQL> select dump(case sysdate when trunc(sysdate) then null
2 else sysdate
3 end) as simple_case
4 , dump(case when sysdate = trunc(sysdate) then null
5 else sysdate
6 end) as searched_case
7 , dump(decode(sysdate, trunc(sysdate), null, sysdate)) as decode
8 from dual;
SIMPLE_CASE
----------------------------------
Typ=12 Len=7: 120,112,12,4,22,18,7
SEARCHED_CASE
----------------------------------
Typ=12 Len=7: 120,112,12,4,22,18,7
DECODE
----------------------------------
Typ=1 Len=19: 50,48,49,50,45,49,50,45,48,52,32,50,49,58,49,55,58,48,54
SQL小提琴
请注意(在 SQL Fiddle 中)已使用会话NLS_DATE_FORMAT将 DATE 转换为字符。
将日期隐式转换为 VARCHAR2 可能会导致问题。如果您打算使用TO_CHAR将日期转换为字符,那么您的查询将在您不期望的地方中断。
SQL> select to_char( decode( sysdate
2 , trunc(sysdate), null
3 , sysdate )
4 , 'yyyy-mm-dd') as to_char
5 from dual;
select to_char( decode( sysdate
*
ERROR at line 1:
ORA-01722: invalid number
SQL小提琴
同样,日期算术不再起作用:
SQL>
SQL>
SQL> select decode(sysdate, trunc(sysdate), null, sysdate) + 1 as decode
2 from dual;
select decode(sysdate, trunc(sysdate), null, sysdate) + 1 as decode
*
ERROR at line 1:
ORA-01722: invalid number
SQL小提琴
有趣的是,如果可能的结果之一为 NULL,则 DECODE 仅将表达式转换为 VARCHAR2。如果默认值为 NULL,则不会发生这种情况。例如:
SQL> select decode(sysdate, sysdate, sysdate, null) as decode
2 from dual;
DECODE
-------------------
2012-12-04 21:18:32
SQL> select dump(decode(sysdate, sysdate, sysdate, null)) as decode
2 from dual;
DECODE
------------------------------------------
Typ=13 Len=8: 220,7,12,4,21,18,32,0
SQL小提琴
请注意,解码返回的数据类型为 13。这没有记录,但我认为它是日期算术等的一种日期类型。
简而言之,尽可能避免 DECODE;您可能不一定会得到您期望的数据类型。引用汤姆凯特的话:
解码有些晦涩——CASE 非常非常清楚。在解码中容易做的事情在 CASE 中容易做,在解码中很难或几乎不可能做的事情在 CASE 中容易做。案例,逻辑明智,胜出。
为了完整起见,DECODE 和 CASE 之间存在两个功能差异。
- DECODE 不能在 PL/SQL 中使用。
CASE 不能用于直接比较空值
SQL> select case null when null then null else 1 end as case1
2 , case when null is null then null else 1 end as case2
3 , decode(null, null, null, 1) as decode
4 from dual
5 ;
CASE1 CASE2 DECODE
---------- ---------- ------
1
SQL小提琴