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

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

上一篇 / 下一篇  2008-04-28 23:56:20 / 个人分类:ORACLE

看到开发区的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)ITPUB个人空间9@;a n$T+O-H
  2  RETURN VARCHAR2 ASITPUB个人空间3u.LA].I+A7\P'@`x
  3  SUBTYPE I IS INT;
!DqaU^kp0  4  N I:=P_DATE_STRING;ITPUB个人空间 }Et7l&n1\%Z
  5  C I:=100;
:LKdp9PUq-z0  6  D I:=MOD(N,C);
+K:w:P2C'K/Q3\y I4M[0  7  Y I:=N/C/C;ITPUB个人空间LTo6D PMBM5k
  8  M I:=MOD(N/C,C);
~:eO-}_0h0  9  Z I:=M+P_MONTHS;
^HW W'C0 10  FUNCTION F(Y I,M I) RETURN IITPUB个人空间$fq%_-B@,|+RptI)p
 11  ASITPUB个人空间K"dBOVo
 12  BEGINITPUB个人空间7}!GI)\Cs TH
 13  RETURN 31-CASE WHEN M IN(4,6,9,11) THEN 1ITPUB个人空间1Y#dW Sar"^
 14  WHEN M!=2 THEN 0
e2\QMFMiu8s0 15  WHEN MOD(Y,4*C)=0 OR MOD(Y,4)=0 AND MOD(Y,C)>0 THEN 2ITPUB个人空间3vDl B2M Hkq8\
 16  ELSE 3
9c|1N o.lVL0 17  END;
-x({;l`-R0 18  END;ITPUB个人空间3pmV P%B ^
 19  BEGIN
\qa4p _8h'T0 20  N:=MOD(MOD(Z,12)+11,12)+1;
'sX(W0r/lO @+~[0 21  Z:=Y+(Z-N)/12;ITPUB个人空间6oW0g F\1dv$O
 22  IF D=F(Y,M) OR D>F(Z,N) THENITPUB个人空间I8S:` |'K9o3f
 23  D:=F(Z,N);ITPUB个人空间n{Zqs.S}.y
 24  END IF;ITPUB个人空间+Qd^ k-}3|
 25  RETURN Z*C*C+N*C+D;ITPUB个人空间]%w ^bt\D"u
 26  END;ITPUB个人空间2}QBXq'|y,i#c
 27  /

函数已创建。

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

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

SQL> SET SERVEROUT ON
mX#Uv&G6b3@0SQL> declare
4K P!cGQQ4ln d0  2    ln  number;ITPUB个人空间 `Bm]:@6u!pUx
  3    ld1 date;
(jr6bR#fF9X4n#`u0  4    ld2 date;ITPUB个人空间vX!xIHQ
  5    ls  varchar2(8);ITPUB个人空间pF^F&D"j;V
  6    lt  number := dbms_utility.get_time;
Bf2L8N[I9I9k0  7    ex exception;
`6S;W{_p1u0  8    i number;ITPUB个人空间\Wi+~])p
  9    j number;
C,P$IoV#x w0 10  beginITPUB个人空间%KD-s-Qe,yFU W s
 11    ld1 := to_date('20080101', 'yyyymmdd');
jVh n;u F0 12    i := 0;
GssO@h5vM0 13    loop
u } Hw/B n;Id$i0 14      exit when i > 800;
c_W ne ZTh+Q-\c9Z0 15      j := -2400;
W XdD2`8G!Du0 16      loopITPUB个人空间,\N5m)n`Dg
 17        exit when j > 2400;ITPUB个人空间6J9N W$DK5E3Z-Q
 18        if to_char(ld1 + i,'dd')= '02' then
'Y W#P7~${c/V"yIYe.L0 19          i := i + 25;ITPUB个人空间+W%BbEb8|)ht
 20        end if;
"k2[X z%yj8un3A0 21        if to_char(add_months(ld1 + i, j), 'yyyymmdd') <>
W!`v%Zh W%sp3o&n0 22           nvl(my_add_months(to_char(ld1 + i, 'yyyymmdd'), j), '*') then
8@9hgT9ZZ%~0 23          dbms_output.put_line('Sorry: stop at p_date_string=' ||ITPUB个人空间"r:P;k-]`n)v9g
 24                               to_char(ld1 + i, 'yyyymmdd') || ',p_months=' || j);ITPUB个人空间5J'vd$Lc4M&EO@ a H N
 25          dbms_output.put_line('my_add_months returned: '||my_add_months(to_char(ld1 + i, 'yyyymmdd'), j) ||
s%X,Hb8O/_m0 26                               ',    add_months returned: ' || to_char(add_months(ld1 + i, j), 'yyyymmdd'));ITPUB个人空间nzsU0{n;A V
 27          raise ex;ITPUB个人空间;Z,^!XR{ F2~.K"g R
 28        end if;
!`h }d*A`0 29        j := j + 1;ITPUB个人空间$}*thp-h
 30      end loop;ITPUB个人空间8oM8V Qd+?
 31      i := i + 1;
Y;M3N)ra0 32    end loop;
"Z p F mz7H%V1[0 33    ln := 0;
SU*`9B X0 34    for c in (select text
E%?8gNF)MPf3s0 35                from user_source
*i8}S'BxTcz0 36               where name = 'MY_ADD_MONTHS'ITPUB个人空间2V1?e+sVOd
 37                 and type = 'FUNCTION') loopITPUB个人空间"c6f:[uo)T4uN
 38      ln := ln + nvl(lengthb(translate(c.text,ITPUB个人空间 ab,D+KI*N%b \ |
 39                                       '*' || chr(9) || chr(10) || chr(13) ||
E6f.is hBD0 40                                       chr(32),ITPUB个人空间+`oMb6h,N1r
 41                                       '*')),
Sz.fi9[m{A0 42                     0);
|2??e8CV'@'u(_0 43    end loop;
q1x ~r/W0 44 
C+h }zQ ZTU!B0 45    lt := (dbms_utility.get_time - lt) / 100;ITPUB个人空间eeA/e8zY _HrS?
 46    dbms_output.put_line('Congratulation ... Code Length: ' || ln ||ITPUB个人空间"w$n%^w.G$w5`1s
 47                         ' Bytes. Times: ' ||ITPUB个人空间?m T?6F }j"E
 48                         to_char(to_date(to_char(lt, 'fm00000'), 'sssss'),ITPUB个人空间2P+W9z8{ bm
 49                                 'hh24:mi:ss'));
;Y"m)xY*j@6n0 50  exception
%SUEs9j;n4F;z0 51    when ex thenITPUB个人空间:Ao W3xo kl"k
 52      null;ITPUB个人空间!o[3l2pD9za9E |1r$m
 53  end;
0[cC!l*L4p*z0 54  /ITPUB个人空间%u7eq-L7@H2l6na
Congratulation ... Code Length: 412 Bytes. Times: 00:00:10

PL/SQL过程已成功完成。

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

 


TAG:

 

评分:0

我来说两句

显示全部

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

Open Toolbar