不使用日期函数实现ADD_MONTHS函数功能

看到开发区的nyfor版主出了一道题,用PL/SQL实现OracleADD_MONTHS的功能,觉得比较有意思,忍不住尝试了一下。

原文如下:http://www.itpub.net/thread-977079-1-1.html

 

 

要求不能使用任何日期函数,不能使用SQL,不能使用Oracle提供的标准包以外的包,只通过标准函数来实现这个功能,且要求源代码尽量短。

经过多次尝试和努力,将字符控制到了420之内,下面贴出这个函数的实现:

SQL> CREATE OR REPLACE FUNCTION MY_ADD_MONTHS(P_DATE_STRING VARCHAR2, P_MONTHS NUMBER)
  2  RETURN VARCHAR2 AS
  3  SUBTYPE I IS INT;
  4  N I:=P_DATE_STRING;
  5  C I:=100;
  6  D I:=MOD(N,C);
  7  Y I:=N/C/C;
  8  M I:=MOD(N/C,C);
  9  Z I:=M+P_MONTHS;
 10  FUNCTION F(Y I,M I) RETURN I
 11  AS
 12  BEGIN
 13  RETURN 31-CASE WHEN M IN(4,6,9,11) THEN 1
 14  WHEN M!=2 THEN 0
 15  WHEN MOD(Y,4*C)=0 OR MOD(Y,4)=0 AND MOD(Y,C)>0 THEN 2
 16  ELSE 3
 17  END;
 18  END;
 19  BEGIN
 20  N:=MOD(MOD(Z,12)+11,12)+1;
 21  Z:=Y+(Z-N)/12;
 22  IF D=F(Y,M) OR D>F(Z,N) THEN
 23  D:=F(Z,N);
 24  END IF;
 25  RETURN Z*C*C+N*C+D;
 26  END;
 27  /

函数已创建。

虽然这个实现不是最短的,但是这个函数中从头到尾只用了一个函数MOD

下面利用nyfor版主提供的测试代码进行测试:

SQL> SET SERVEROUT ON
SQL> declare
  2    ln  number;
  3    ld1 date;
  4    ld2 date;
  5    ls  varchar2(8);
  6    lt  number := dbms_utility.get_time;
  7    ex exception;
  8    i number;
  9    j number;
 10  begin
 11    ld1 := to_date('20080101', 'yyyymmdd');
 12    i := 0;
 13    loop
 14      exit when i > 800;
 15      j := -2400;
 16      loop
 17        exit when j > 2400;
 18        if to_char(ld1 + i,'dd')= '02' then
 19          i := i + 25;
 20        end if;
 21        if to_char(add_months(ld1 + i, j), 'yyyymmdd') <>
 22           nvl(my_add_months(to_char(ld1 + i, 'yyyymmdd'), j), '*') then
 23          dbms_output.put_line('Sorry: stop at p_date_string=' ||
 24                               to_char(ld1 + i, 'yyyymmdd') || ',p_months=' || j);
 25          dbms_output.put_line('my_add_months returned: '||my_add_months(to_char(ld1 + i, 'yyyymmdd'), j) ||
 26                               ',    add_months returned: ' || to_char(add_months(ld1 + i, j), 'yyyymmdd'));
 27          raise ex;
 28        end if;
 29        j := j + 1;
 30      end loop;
 31      i := i + 1;
 32    end loop;
 33    ln := 0;
 34    for c in (select text
 35                from user_source
 36               where name = 'MY_ADD_MONTHS'
 37                 and type = 'FUNCTION') loop
 38      ln := ln + nvl(lengthb(translate(c.text,
 39                                       '*' || chr(9) || chr(10) || chr(13) ||
 40                                       chr(32),
 41                                       '*')),
 42                     0);
 43    end loop;
 44 
 45    lt := (dbms_utility.get_time - lt) / 100;
 46    dbms_output.put_line('Congratulation ... Code Length: ' || ln ||
 47                         ' Bytes. Times: ' ||
 48                         to_char(to_date(to_char(lt, 'fm00000'), 'sssss'),
 49                                 'hh24:mi:ss'));
 50  exception
 51    when ex then
 52      null;
 53  end;
 54  /
Congratulation ... Code Length: 412 Bytes. Times: 00:00:10

PL/SQL 过程已成功完成。

代码本身比较简单,只不过为了缩短代码的数量,使用了一些小技巧。当然这个实现肯定还有很多可以优化的地方,这里希望能起到一个抛砖引玉的作用。

 

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/4227/viewspace-255480/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/4227/viewspace-255480/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值