/* 由大小月份引起的日期计算时值得注意的一个问题 */
SQL>
SQL> SELECT DATE'2012-10-30' 上月30日, DATE'2012-11-30' 今日,add_months( DATE'2012-10-30',1) 上月增加一月,
2 add_months( DATE'2012-11-30',-1) 本月减少一月 FROM dual;
上月30日 今日 上月增加一月 本月减少一月
----------- ----------- ------------ ------------
2012-10-30 2012-11-30 2012-11-30 2012-10-31
结果表明:10-30加1个月为11-30,而11-30减1个月结果却为10-31,也就是说大月30日增加1个月结果为小月30日,小月减少1个月结果为大月31日。
oracle的日期如此计算应该说是比较合理的,但在开发如计算同比等指标有一点值得注意,看下面的例子:
SQL> SELECT id,pub_date FROM mm;
ID PUB_DATE
--------------------------------------- -----------
1 2012-11-30
2 2012-10-31
3 2012-10-30
SQL> SELECT m1.pub_date m1date, m2.pub_date m2date ,m1.id/m2.id
2 FROM mm m1 ,mm m2
3 WHERE add_months(m2.pub_date,-1)=m1.pub_date;
M1DATE M2DATE M1.ID/M2.ID
----------- ----------- -----------
2012-10-31 2012-11-30 2
只有一条记录,11-30与10-30比较
SQL> SELECT m1.pub_date m1date, m2.pub_date m2date ,m1.id/m2.id
2 FROM mm m1 ,mm m2
3 WHERE add_months(m1.pub_date,1)=m2.pub_date;
M1DATE M2DATE M1.ID/M2.ID
----------- ----------- -----------
2012-10-30 2012-11-30 3
2012-10-31 2012-11-30 2
生成了两条记录,11-30与10-30、10-31都对应上了,既然大小月份会引起该问题,那么遇到2月平闰月的情况,情况也是类似的。
-- 向表中插入一些测试数据
SQL> SELECT id,pub_date FROM mm;
ID PUB_DATE
--------------------------------------- -----------
1 2012-11-30
2 2012-10-31
4 2012-1-28
5 2012-1-29
6 2012-1-30
7 2012-1-31
8 2012-2-28
9 2012-2-29
3 2012-10-30
9 rows selected
SQL>
SQL> SELECT m1.pub_date m1date, m2.pub_date m2date ,m1.id/m2.id
2 FROM mm m1 ,mm m2
3 WHERE add_months(m2.pub_date,-1)=m1.pub_date AND m2.id=8;
M1DATE M2DATE M1.ID/M2.ID
----------- ----------- -----------
2012-1-28 2012-2-28 0.5
SQL> SELECT m1.pub_date m1date, m2.pub_date m2date ,m1.id/m2.id
2 FROM mm m1 ,mm m2
3 WHERE add_months(m1.pub_date,1)=m2.pub_date AND m2.id=8;
M1DATE M2DATE M1.ID/M2.ID
----------- ----------- -----------
2012-1-28 2012-2-28 0.5
日期为2012-2-28日参与计算时均只有一条,不受大小月份的影响,再看29日的情形:
SQL> SELECT m1.pub_date m1date, m2.pub_date m2date ,m1.id/m2.id
2 FROM mm m1 ,mm m2
3 WHERE add_months(m2.pub_date,-1)=m1.pub_date AND m2.id=9;
M1DATE M2DATE M1.ID/M2.ID
----------- ----------- -----------
2012-1-31 2012-2-29 0.777777777
2012-2-29向前推1个月为2012-1-31,也只有1条记录,这与上面测试结果是一致的。
SQL> SELECT m1.pub_date m1date, m2.pub_date m2date ,m1.id/m2.id
2 FROM mm m1 ,mm m2
3 WHERE add_months(m1.pub_date,1)=m2.pub_date AND m2.id=9;
M1DATE M2DATE M1.ID/M2.ID
----------- ----------- -----------
2012-1-29 2012-2-29 0.555555555
2012-1-30 2012-2-29 0.666666666
2012-1-31 2012-2-29 0.777777777
日期2012-1-29向后推1个月则产生了3条记录。
因此,在开发过程中计算月同比等指标时须注意,若非严格要求可采用30天时间差或利用当前日期减少1个月来来消除此现象。