有一个sql语句:select to_date(

case substr(to_char(to_date('2010-11-21','yyyy-mm-dd hh24:mi:ss'),'yyyymmdd'),7,2) 
when '01' then '20000102' 
else to_char(to_date('2010-11-21','yyyy-mm-dd hh24:mi:ss'),'yyyymmdd') end 
)
,'yyyy-mm-dd hh24:mi:ss') - interval '1' day
from dual
sql语句的作用
1、首先判断出入的字符串型的日期数据【2010-11-21】是否是1号,如果是1号,返回20000102;否则返回输入值
2、把第一步的输出结果格式化为日期型
3、把第二步的结果减去一天,即得到输入日期的前一天说明:
1、有些同学会说substr判断多余,先把字符串型的格式化为日期型,再吧日期型格式化为字符串。这里说明一下,因为传入的字符串型的日期值不一定是【2010-11-21】,有可能输入的是【20101121】,所以这里判断复杂了。也有更好的算法,但这里暂时按语句里面的算法来看吧,目的只是为了出现后面说的问题。问题:
以上的这个sql语句在9i的数据库中可以直接执行,得到结果。但是这段语句在10g的数据库中就报错了,报错信息:
ORA-01841: (full) year must be between -4713 and +9999, and not be 0自己处理的过程:
1、我把每一步都独立出来单独执行,发现在10g的数据库里,一直到select to_date(

case substr(to_char(to_date('2010-11-21','yyyy-mm-dd hh24:mi:ss'),'yyyymmdd'),7,2) 
when '01' then '20000102' 
else to_char(to_date('2010-11-21','yyyy-mm-dd hh24:mi:ss'),'yyyymmdd') end 
)
,'yyyy-mm-dd hh24:mi:ss')
from dual都可以执行成功,一旦加上  【- interval '1' day】,就报错了。但是9i中始终都可以得到结果。2、后来,我把substr简化了,直接从【2010-11-21】这样的格式中截取字符串判断,然后再加上【- interval '1' day】,这次就可以执行过去了,语句为:select to_date(

case substr('2010-11-21',9,2) 
when '01' then '20000102' 
else to_char(to_date('2010-11-21','yyyy-mm-dd hh24:mi:ss'),'yyyymmdd') end 
)
,'yyyy-mm-dd hh24:mi:ss') - interval '1' day
from dual
为什么会这样?是不是substr的语句太复杂了,oracle就会报错?

解决方案 »

  1.   

    SQL> select to_date(
      2  (  
      3  case substr(to_char(to_date('2010-11-21','yyyy-mm-dd'),'yyyymmdd'),7,2)  
      4  when '01' then '20000102'  
      5  else to_char(to_date('2010-11-21','yyyy-mm-dd hh24:mi:ss'),'yyyymmdd') end 
      6  )
      7  ,'yyyy-mm-dd hh24:mi:ss') - interval '1' day
      8  from dual
      9  /TO_DATE((CASES
    --------------
    20-11月-10
      

  2.   

    --红色部分你跟本就没指定时间 只有日期 而你后面却'2010-11-21','yyyy-mm-dd hh24:mi:ss')select to_date(
    (  
    case substr(to_char(to_date('2010-11-21','yyyy-mm-dd hh24:mi:ss'),'yyyymmdd'),7,2)  
    when '01' then '20000102'  
    else to_char(to_date('2010-11-21','yyyy-mm-dd hh24:mi:ss'),'yyyymmdd') end  
    )
    ,'yyyy-mm-dd hh24:mi:ss') - interval '1' day
    from dual
      

  3.   

    --or
    select to_date(
    (  
    case substr(to_char(to_date('2010-11-21 00:00:00','yyyy-mm-dd hh24:mi:ss'),'yyyymmdd'),7,2)  
    when '01' then '20000102'  
    else to_char(to_date('2010-11-21','yyyy-mm-dd hh24:mi:ss'),'yyyymmdd') end  
    )
    ,'yyyy-mm-dd hh24:mi:ss') - interval '1' day
    from dual
      

  4.   


    为什么substr那里加了【 00:00:00】,而【else to_char(to_date('2010-11-21','yyyy-mm-dd hh24:mi:ss'),'yyyymmdd') end】中不加,却能执行过去?都是转成date型,上下两个地方有什么区别么?