看起来简单的CASE表达式和DECODE函数是等价的,并且它们返回的结果应该是相同的.是吗?
该文档有关于简单CASE表达式的以下内容:
简单的CASE表达式返回selector_value与selector匹配的第一个结果.不评估剩余表达式.如果没有selector_value与selector匹配,则CASE表达式返回else_result(如果存在),否则返回NULL.
将其与DECODE函数进行比较,描述似乎相同.
DECODE将expr逐个与每个搜索值进行比较.如果expr等于搜索,则Oracle数据库返回相应的结果.如果未找到匹配项,则Oracle返回默认值.如果省略default,则Oracle返回null.
由于搜索到的CASE表达式可以等同于简单,因此可以将其解释为相同.
这三个陈述似乎都返回相同的结果,0.
select case 1 when 2 then null else 0 end as simple_case
, case when 1 = 2 then null else 0 end as searched_case
, decode(1, 2, null, 0) as decode
from dual
Run Code Online (Sandbox Code Playgroud)
简单的CASE表达式和DECODE函数(以及在特定情况下搜索的CASE表达式)是否总是返回相同的结果?
Ben*_*Ben 24
简短的回答,没有.
稍微长一点的答案就差不多了.
只显示从每个语句获得的结果是相同的.如果我们使用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
Run Code Online (Sandbox Code Playgroud)
您可以看到DECODE的数据类型是1,而两个CASE语句"返回"数据类型2.使用Oracle的数据类型摘要,DECODE返回VARCHAR2(数据类型1),而CASE语句是"返回" "数字(数据类型2).
我认为这是因为,正如名称所示,DECODE是一个函数而CASE不是,这意味着它们在内部以不同的方式实现.没有真正的方法来证明这一点.
你可能认为这并没有真正影响任何事情.如果你需要它是一个数字,Oracle会隐式地将字符转换为隐式转换规则下的数字,对吧?这也不是真的,它在UNION中不起作用,因为数据类型必须相同; Oracle不会进行任何隐式转换,以便您轻松完成任务.其次,这是Oracle关于隐式转换的内容:
Oracle建议您指定显式转换,而不是依赖隐式或自动转换,原因如下:
使用显式数据类型转换函数时,SQL语句更易于理解.
隐式数据类型转换可能会对性能产生负面影响,尤其是当列值的数据类型转换为常量的数据类型而不是相反时.
隐式转换取决于它发生的上下文,并且在每种情况下可能无法以相同的方式工作.例如,从datetime值到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;
Run Code Online (Sandbox Code Playgroud)
再一次,在此查询上使用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
Run Code Online (Sandbox Code Playgroud)
注意(在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
Run Code Online (Sandbox Code Playgroud)
同样,日期算术不再有效:
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
Run Code Online (Sandbox Code Playgroud)
有趣的是,如果其中一个可能的结果为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
Run Code Online (Sandbox Code Playgroud)
请注意,DECODE返回的数据类型为13.这没有记录,但我认为是日期算术等的日期类型.
简而言之,如果可能,请避免使用DECODE; 您可能不一定得到您期望的数据类型.要引用汤姆凯特:
解码有点模糊 - CASE非常清楚.在CASE中很容易做到易于解码的事情,在CASE中很容易做到解码困难或几乎无法做到的事情.逻辑明智的CASE赢得了胜利.
为了完成,DECODE和CASE之间存在两个功能差异.
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
Run Code Online (Sandbox Code Playgroud)
APC*_*APC 13
Ben对DECODE和CASE之间的差异写了一个冗长的答案.他演示了DECODE和CASE可能会为显然相同的值集返回不同的数据类型,而没有正确解释为什么会发生这种情况.
DECODE()是非常规范的:它始终是第一个结果参数的数据类型.Oracle将隐式转换应用于所有其他结果参数.如果(例如)第一个结果参数是数字且默认值是日期,则会抛出错误.
ORA-00932: inconsistent datatypes: expected NUMBER got DATE
Run Code Online (Sandbox Code Playgroud)
文档中对此进行了描述:了解更多信息.
在第一个场景中,第一个结果参数为NULL,Oracle决定将其视为VARCHAR2.如果我们更改它以使第一个结果参数为数字且默认值为null,则DECODE()语句将返回NUMBER; DUMP()证明了这一点.
而CASE坚持所有返回的值都具有相同的数据类型,如果不是这样,则会抛出编译错误.它不会应用隐式转换.这也包含在文档中.在这里阅读.
差异归结为此.将运行以下DECODE语句,CASE语句将不会:
select decode(1, 1, 1, '1') from dual;
select case 1 when 1 then 1 else '1' end from dual;
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
17760 次 |
| 最近记录: |