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")