Chinaunix首页 | 论坛 | 博客
  • 博客访问: 103118106
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类: DB2/Informix

2008-04-03 21:07:49

Informix数据库由于其良好的动态扩展性,在各个行业被广泛使用!
 
       但Informix数据库有个致命缺陷,哪怕是在现在比较新的Informix Online 9版本上仍然存在问题,就是Informix对于日期处理上的“绝对弱智”,只要需要处理日期边界问题的时候,都会出错!
 
       比如你使用 SELECT  DATE("20000229")- 1 UNITS YEAR FROM dual ,从“2000/02/29”往前推算1年,而1999年,不是闰年,其2月份只有28天,这时就会报错(错误号1267)(出错信息:1267: The result of a datetime computation is out of range.)
       其它比如你从7月31日往前推1月,从1月31日/1月30日往后推1月,都会碰到日期边界处理出错的问题,给项目开发带来一些困扰!
 
       由于手头的项目需要进行日期的灵活计算,所以我考虑针对这些日期边界处理错误号(-1267、-1263、-1210)设置陷阱进行捕获,发现日期边界超限,则将日期往前推算,直到出现一个正常合法的日期为止!以下我改良的日期计算存储过程算法,可以按照“日”“月”“季”“半年”“年”灵活的向前向后推算日期。
    
CREATE PROCEDURE  p_random_date (
   v_random_date   DATE,
   v_pass     INT,
   v_mode    VARCHAR(1) DEFAULT 'M'
)
RETURNING DATE;
-- 参数 任意一天,经过月/天/年数,日期标度(月M,日D,年Y,半年H,季Q))
-- return 任意一天经过N月/天/年后的对应日,若对应日不存在,则往前推
 DEFINE tmp_random_date DATE;
 DEFINE rtndate  DATE;
        DEFINE v_pass1          INT;
 DEFINE esql, eisam     INT;
 DEFINE etext           VARCHAR(80);
 
 ON EXCEPTION SET esql, eisam, etext
          IF esql < 0  THEN
             RAISE EXCEPTION esql, eisam, etext;
          END IF
     END EXCEPTION 
  
 LET tmp_random_date = v_random_date;
 LET rtndate = NULL;
        LET v_pass1 = 0;
        IF v_mode = 'H' THEN
           LET v_pass = v_pass*6;
        ELIF v_mode = 'Q' THEN
           LET v_pass = v_pass*3;
        END IF;
{
 SET DEBUG FILE TO "random.log";
 TRACE ON;
}
 WHILE 1 = 1
 ON EXCEPTION SET esql
           IF esql = -1267 THEN
       LET tmp_random_date = tmp_random_date -1;
           ELIF esql = -1263 THEN 
  --处理ONLINE7.3x BUG: 2004/02/20 -14(或15) UNITS MONTH出错 
              LET v_pass1 = v_pass1 + 1;
           ELIF esql = -1210 THEN 
         --处理ONLINE7.3x BUG: 2004/02/20 -14(或15) UNITS MONTH出错 
              LET v_pass1 = v_pass1 + 1;
    ELSE
  RAISE EXCEPTION esql;
           END IF;
 END EXCEPTION;
 
 IF v_mode = 'Y' THEN
  LET rtndate = tmp_random_date+v_pass UNITS YEAR;
 ELIF v_mode = 'D' THEN
  LET rtndate = tmp_random_date+v_pass UNITS DAY;
 ELSE        -- v_mode IN ('M','H','Q')
  LET rtndate = (tmp_random_date+(v_pass-v_pass1) UNITS MONTH)+
                                  v_pass1 UNITS MONTH;
 END IF
  EXIT WHILE;
 END WHILE;
 RETURN rtndate;
END PROCEDURE;
 
   调用举例如下: 
 往前1个月    EXECUTE PROCEDURE p_random_date("20000229",-1,"M")  
 往后60天      EXECUTE PROCEDURE p_random_date("20000229",60,"D")   
 往前2 年       EXECUTE PROCEDURE p_random_date("20000229",-2,"Y")
阅读(568) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~