我申请这个blog是为了督促自己,把自己平时的一些想法和思考结果保留下来。 本博客所有内容均为原创,如有转载请注明作者和出处

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

上一篇 / 下一篇  2008-05-31 23:53:38 / 个人分类:ORACLE

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

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

不使用日期函数实现ADD_MONTHS函数功能:http://yangtingkun.itpub.net/post/468/460788

在原有的基础上做了一点小改动。

 

 

由于这个东西比较耗费精力,因此自从上次的函数实现之后就没有再花功夫去研究。

不过从其他人那里学到了一个函数的用法,可以在不改变现有算法的情况下,再次减少源代码的长度:

SQL> CREATE OR REPLACE FUNCTION MY_ADD_MONTHS(P_DATE_STRING VARCHAR2, P_MONTHS NUMBER)ITPUB个人空间s#yqx&G$G(gQ
  2  RETURN VARCHAR2 AS
i/p;j"]Q ^0  3  SUBTYPE I IS INT;ITPUB个人空间H'T0{il5G)zh|E t
  4  N I:=P_DATE_STRING;
-c)Ij_-EXad_0  5  C I:=100;ITPUB个人空间/[.t L4ZsD8[
  6  D I:=N MOD C;
FR#q3W4S9k(j0  7  Y I:=N/C/C;ITPUB个人空间7D[;V(Td9u/n'S e&Zb
  8  M I:=N/C MOD C;ITPUB个人空间:F+lk5yrPZE%Wr
  9  Z I:=M+P_MONTHS;ITPUB个人空间9S(r!Y$ZB0B7d%Fk0K KL
 10  FUNCTION F(Y I,M I) RETURN IITPUB个人空间&v q Q1MsS&[2R
 11  ASITPUB个人空间8vDULKL
 12  BEGIN
aRX+@@1}0 13  RETURN 31-CASE WHEN M IN(4,6,9,11) THEN 1
8B}q)QP|9oZv0 14  WHEN M!=2 THEN 0ITPUB个人空间6p!mn*A&e D&T^
 15  WHEN Y MOD 400 = 0 OR Y MOD 4 = 0 AND Y MOD C > 0 THEN 2
NE&Gd%C ^,Hp0 16  ELSE 3
`2@'t? ]Y.s?0 17  END;ITPUB个人空间^GA/t6CH
 18  END;
#~HVw ~ \+R^'j/XEC]#K0 19  BEGIN
X Tz7B1k ^Npl0 20  N:=(Z MOD 12 + 11) MOD 12 + 1;ITPUB个人空间%S$b@*{+mM(]M
 21  Z:=Y+(Z-N)/12;
Cm2^ R{0 22  IF D=F(Y,M) OR D>F(Z,N) THENITPUB个人空间4J,lCaTA2J0G U
 23  D:=F(Z,N);
"n`Ko1L(r0 24  END IF;
9XdkKT5k5~l O R0 25  RETURN Z*C*C+N*C+D;
V!z3H5x7h{EkMgdPl0 26  END;
ob.Gd4e.]1p[0 27  /

函数已创建。

SQL> SET SERVEROUT ON
kJ ugb5O0SQL> declareITPUB个人空间-_ n%xT4r;@v
  2    ln  number;
"~@1`lO3E#q0  3    ld  date;
V'v2_R@9qAC0  4    ls1 varchar2(8);
m[Gu$F }*Jl*P0  5    ls2 varchar2(8);ITPUB个人空间zg.o1B/Ee
  6    lt  number := dbms_utility.get_time;ITPUB个人空间(T1ZL!C;Zd
  7    ex exception;ITPUB个人空间?b0]}Sm
  8    y number;
-h^$?t%A,\&t s#D3K%~0  9    m number;ITPUB个人空间5}@g~m1M
 10    d number;
5U.D7x1P5U$KKl4H0 11    j number;
})TS8pn B%]Te8q0 12  beginITPUB个人空间`.XihK%[
 13    for j in 0 .. 5000 loopITPUB个人空间Q+kAP6j/GTE^
 14      for y in 2000 .. 2001 loop
\O2QQ&PV,W6W0 15        for m in 2 .. 4 loopITPUB个人空间I^4i-|0[i:~._$x
 16          for d in 28 .. 31 loop
,Mfsod n,a0 17            begin
bd7@abf0 18              ls1 := y || '0' || m || d;
W7\SH2O0 19              beginITPUB个人空间i cn{o$T({"t
 20                ld  := to_date(ls1, 'yyyymmdd');ITPUB个人空间B1I8VKA
 21              exceptionITPUB个人空间2r a'Q-U3o+J4T.@C
 22                when others then
C XR'K&\vP"x5M'[0 23                  exit;
C+h,`shm }0 24              end;
Xr3A0f+m0 25              ld  := add_months(ld, j);
!O;tl9Uia SD0 26              ls2 := to_char(ld, 'yyyymmdd');ITPUB个人空间8vq8EeqW^!wj
 27              if nvl(my_add_months(ls1, j), '*') <> ls2 then
tOd#q _ U6T?0 28                dbms_output.put_line('Sorry: stop at p_date_string=' || ls1 ||ITPUB个人空间l)~5N*i#g`D
 29                                     ',p_months=' || j);ITPUB个人空间ED7q(_"~%J)Eir
 30                dbms_output.put_line('my_add_months returned: ' ||ITPUB个人空间G.Uo&E8a3in
 31                                     my_add_months(ls1, j));
g_a9su\1Q E0 32                dbms_output.put_line('add_months returned: ' || ls2);ITPUB个人空间Wy-y(e$lw"h
 33                raise ex;
LPD%U a0 34              end if;ITPUB个人空间D(a~[V*`
 35           ITPUB个人空间V"R&?'b,d*W'k;l.q
 36              ls1 := to_char(add_months(ld, -j), 'yyyymmdd');
,fhU8C X|'sn0 37              if nvl(my_add_months(ls2, -j), '*') <> ls1 then
N ]x DrC0 38                dbms_output.put_line('Sorry: stop at p_date_string=' || ls2 ||
fB`B!O?b#`:ED0 39                                     ',p_months=' || -j);ITPUB个人空间f_;uj b.u7\3F1x
 40                dbms_output.put_line('my_add_months returned: ' ||ITPUB个人空间 n l6aZ[O3\B
 41                                     my_add_months(ls2, -j));ITPUB个人空间,DqD my(_8M{
 42                dbms_output.put_line('add_months returned: ' || ls1);
#f/yz%b ]On&N0 43                raise ex;
`8U h?!O8rgI0 44              end if;
O`~%t L8T(Q6^W0 45            exception
2s;@8tt*kq|0 46              when ex then
AZ T*D3| po0 47                raise;
$y|"umEW MV0N%l&S0 48              when others then
z%`;i:FM;h4^%Jl0 49                raise;ITPUB个人空间6ph rK!mH
 50            end;ITPUB个人空间,C7ayZ c X5Q7C
 51          end loop;ITPUB个人空间 U$\ADM E
 52        end loop;
N.Syj/_0 53      end loop;ITPUB个人空间jz5T X1l%Uvxp
 54    end loop;
;gi OPh%OO0 55    ln := 0;ITPUB个人空间\:][z6_0Q
 56    for c in (select textITPUB个人空间6S&c s.J.h*h
 57                from user_sourceITPUB个人空间2ol8i4K9U4c-q dh
 58               where name = 'MY_ADD_MONTHS'
(pB7wX M[l d2n*Q7M0 59                 and type = 'FUNCTION') loop
e&sE*s?0 60      ln := ln + nvl(lengthb(translate(c.text,ITPUB个人空间fl.Au:R,s3N%{2Q
 61                                       '*' || chr(9) || chr(10) || chr(13) ||ITPUB个人空间$te z&n#MTQ;S2s(Wl#W
 62                                       chr(32),
H'J-KMfm0 63                                       '*')),
#|n D4D g0_0ms0 64                     0);
B]3|?Z0 65    end loop;ITPUB个人空间2pc*u,Z&L ~
 66    lt := (dbms_utility.get_time - lt) / 100;ITPUB个人空间 G(hy,jTrs$Fa"T
 67    dbms_output.put_line('Congratulation ... Code Length: ' || ln ||ITPUB个人空间4m!qLz EpJ
 68                         ' Bytes. Times: ' ||
[+f+~ e:GI}!}+^{0 69                         to_char(to_date(to_char(lt, 'fm00000'), 'sssss'),ITPUB个人空间W` Cv SC2z D
 70                                 'hh24:mi:ss'));
"D+~)i#O'F@0 71  exceptionITPUB个人空间3O!rW{vT @C
 72    when ex thenITPUB个人空间VT)k[$c~n
 73      null;
-t(AC:@-r(i*vg0 74  end;
$NER:Nr}UZ"e0 75  /
M7\p6Rj|0Congratulation ... Code Length: 393 Bytes. Times: 00:00:03

PL/SQL过程已成功完成。

10gPLSQL中,MOD(A,B)可以写为A MOD B,利用这种方法将源代码的最终代码缩短到了400之内。

不过如果再想缩短就必须修改算法了。

 


TAG:

 

评分:0

我来说两句

显示全部

:loveliness: :handshake :victory: :funk: :time: :kiss: :call: :hug: :lol :'( :Q :L ;P :$ :P :o :@ :D :( :)

Open Toolbar