看到开发区的nyfor版主出了一道题,用PL/SQL实现Oracle的ADD_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/