<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    Decode360's Blog

    業精于勤而荒于嬉 QQ:150355677 MSN:decode360@hotmail.com

      BlogJava :: 首頁 :: 新隨筆 :: 聯系 ::  :: 管理 ::
      302 隨筆 :: 26 文章 :: 82 評論 :: 0 Trackbacks
    http://www.itpub.net/viewthread.php?tid=977079&extra=page%3D1%26amp%3Bfilter%3Ddigest
    ?
    ??? 很久以前看過的一個帖子,今天又翻到了,覺得還挺有意思的,摘錄一下:
    ?
    ?
    -----------------------
    ?
    題目: 請模擬出 Oracle 中 Add_Months 函數功能的一個自定義函數.
    要求:
    1. 函數申明固定為:
    create or replace function my_add_months(p_date_string varchar2,
    ???????????????????????????????????????? p_months????? number)
    ? return varchar2
    ? 不允許更改.
    ?
    2. 代碼中禁止申明日期類型的變量, 禁止使用一切與日期有關的類型轉換及函數,禁止使用Oracle提供的Package, 只能使用 Oracle 的標準函數

    3. 不求代碼的效率高效, 但也不能太低.
    ?
    4. 使用你可以使用的一切手段, 將源代碼縮短, 不考慮編譯后的代碼長度, 這里只要求源代碼最短.
    ?
    5. 代碼的長度以扣除其中的空白(空格, 回車換行, TAB鍵)后的字節長度.
    ?
    6. 傳入的日期字符串格式為 yyyymmdd, 增加的月份數傳入整數,? 函數內部你不需要檢核傳入的日期字符串是否有效(一定傳入有效的), 月份數也不用考慮帶小數的情況, 返回的日期字符串格式依然為 yyyymmdd
    ?
    7. 寫完函數后, 請用以下代碼進行測試, 希望運行時間不要太長哦.
    ?
    8. 只把測試結果貼出來, 函數代碼先不貼.
    ?
    9. 運算結果日期年不會超過9999, 也不會小于1600.
    http://www.itpub.net/thread-977394-1-1.html 中提到1582年前使用的是凱撒時期制定的儒略歷,4年一閏,這個屬歷史問題, 我們這里不考慮.
    ?
    10. 函數代碼中禁止使用SQL語句.
    ?
    ?
    -----------------------
    ?
    ?
    測試腳本:
    ?

    set serverout on

    ?

    declare

    ? ln? number ;

    ? ld? date ;

    ? ls1 varchar2 ( 8 );

    ? ls2 varchar2 ( 8 );

    ? lt? number := dbms_utility.get_time;

    ? ex exception ;

    ? y number ;

    ? m number ;

    ? d number ;

    ? j number ;

    begin

    ? for j in 0 .. 5000 loop

    ??? for y in 2000 .. 2001 loop

    ????? for m in 2 .. 4 loop

    ??????? for d in 28 .. 31 loop

    ????????? begin

    ??????????? ls1 := y || '0' || m || d;

    ??????????? begin

    ????????????? ld? := to_date(ls1, 'yyyymmdd' );

    ??????????? exception

    ????????????? when others then

    ??????????????? exit ; -- 過濾所有格式外的日期

    ??????????? end ;

    ??????????? -- 正的月份計算驗證

    ??????????? ld? := add_months(ld, j);

    ??????????? ls2 := to_char(ld, 'yyyymmdd' );

    ??????????? if nvl(my_add_months(ls1, j), '*' ) <> ls2 then

    ????????????? dbms_output.put_line( 'Sorry: stop at p_date_string=' || ls1 ||

    ?????????????????????????????????? ',p_months=' || j);

    ????????????? dbms_output.put_line( 'my_add_months returned: ' ||

    ?????????????????????????????????? my_add_months(ls1, j));

    ????????????? dbms_output.put_line( 'add_months returned: ' || ls2);

    ????????????? raise ex;

    ??????????? end if ;

    ??????????? -- 負的月份計算驗證

    ??????????? ls1 := to_char(add_months(ld, -j), 'yyyymmdd' );

    ??????????? if nvl(my_add_months(ls2, -j), '*' ) <> ls1 then

    ? ???????????? dbms_output.put_line( 'Sorry: stop at p_date_string=' || ls2 ||

    ?????????????????????????????????? ',p_months=' || -j);

    ????????????? dbms_output.put_line( 'my_add_months returned: ' ||

    ?????????????????????????????????? my_add_months(ls2, -j));

    ????????????? dbms_output.put_line( 'add_months returned: ' || ls1);

    ????????????? raise ex;

    ??????????? end if ;

    ????????? exception

    ??????????? when ex then

    ????????????? raise ;

    ??????????? when others then

    ????????????? raise ;

    ????????? end ;

    ??????? end loop ;

    ????? end loop ;

    ??? end loop ;

    ? end loop ;

    ? -- 計算函數的字符個數

    ? ln := 0 ;

    ? for c in ( select text

    ????????????? from user_source

    ???????????? where name = 'MY_ADD_MONTHS'

    ?????????????? and type = 'FUNCTION' ) loop

    ??? ln := ln + nvl(lengthb(translate(c.text,

    ???????????????????????????????????? '*' || chr( 9 ) || chr( 10 ) || chr( 13 ) || chr( 32 ),

    ??????????????????????????????????????????? -- 除去所有的空格、回車、換行、 tab

    ???????????????????????????????????? '*' )),

    ?????????????????? 0 );

    ? end loop ;

    ? lt := (dbms_utility.get_time - lt) / 100 ;

    ? dbms_output.put_line( 'Congratulation ... Code Length: ' || ln ||

    ?????????????????????? ' Bytes. Times: ' ||

    ?????????????????????? to_char(to_date(to_char(lt, 'fm00000' ), 'sssss' ),

    ?????????????????????????????? 'hh24:mi:ss' ));

    exception

    ? when ex then

    ??? null ;

    end ;

    /

    ?


    ?
    -----------------------
    ?
    ?
    隨便挑了一個答案來看看,確實是要耗費很多精力的事情:
    ?
    --sdxiong

    CREATE OR REPLACE FUNCTION MY_ADD_MONTHS(P_DATE_STRING VARCHAR2 ,

    ???????????????????????????????????????? P_MONTHS????? NUMBER )

    ? RETURN VARCHAR2 IS

    ? H INT := 100 ;

    ? S INT := P_DATE_STRING;

    ? Y INT := S/H/H;

    ? M INT := S/H MOD H;

    ? D INT := S MOD H;

    ?

    ? PROCEDURE P IS

    ? BEGIN

    ??? S := 28 + 3232332323030 / 10 **M MOD 10 ; -- 每個月最后一天

    ??? IF M= 2 AND (Y MOD 400 = 0 OR Y MOD 4 < Y MOD H / H) THEN -- 判斷 Y 是否閏年

    ?????? S := 29 ;

    ??? END IF ;

    ? END ;

    ?

    BEGIN

    ?

    ? P;

    ? D := D + D * INSTR(D,S); -- D 為月末,則不需要這個 D ,取新月份的月末期

    ?

    ? M := Y* 12 +M+P_MONTHS;

    ? Y := M/ 12 -.55; -- 計算新年份 ( 保證不進位或退位 ) ,用 Y:=(M-7)/12 好理解一些

    ? M := M-Y* 12 ; -- 計算新月份

    ?

    ? P; -- 計算新月份的月末

    ?

    ? RETURN Y*H*H + M*H + LEAST(D,S);

    ?

    END ;

    /

    ?
    ?
    -----------------------
    ?
    ?
    其它腳本:
    ?

    /**********************
    nyfor:
    **********************/

    create or replace function my_add_months
    (
    ?? p_date_string varchar2,
    ?? p_months????? number
    ) return varchar2 is
    ?? c int := 100;
    ?? a int := p_date_string;
    ?? y int := a / c / c;
    ?? m int := a / c - y * c;
    ?? t int;
    ?? procedure p is
    ?? begin
    ????? t := substr(525454554545, m, 1);
    ????? t := t + 26 + 1 / (t + mod(y, 4) + instr(0, mod(y, c)) * mod(y, 400));
    ?? end;
    begin
    ?? p;
    ?? a := mod(a, c);
    ?? a := trunc(a / t) * c + a;
    ?? m := m + p_months + y * 12 - 7;
    ?? y := m / 12;
    ?? m := m - y * 12 + 7;
    ?? p;
    ?? return y * c * c + m * c + least(a, t);
    end;

    --如果要確保取出每一個隱式轉換,包含精度的轉換, 也會增加很多字節的. 我的轉換后如下:
    create or replace function my_add_months
    (
    ?? p_date_string varchar2,
    ?? p_months????? number
    ) return varchar2 is
    ?? c int := 100;
    ?? a int := to_number(p_date_string);
    ?? y int := round(to_number(a) / c / c);
    ?? m int := round(to_number(a) / c - y * c);
    ?? t int;
    ?? procedure p is
    ?? begin
    ????? t := to_number(substr('525454554545', m, 1));
    ????? t := round(t + 26 + 1 / (t + mod(y, 4) + instr(0, mod(y, c)) * mod(y, 400)));
    ?? end;
    begin
    ?? p;
    ?? a := mod(to_number(a), c);
    ?? a := trunc(to_number(a) / t) * c + to_number(a);
    ?? m := m + p_months + y * 12 - 7;
    ?? y := round(m / 12);
    ?? m := m - y * 12 + 7;
    ?? p;
    ?? return to_char(y * c * c + m * c + least(to_number(a), t));
    end;
    --加入所有的顯示轉換及精度轉換后 475 Bytes.
    ?
    ?
    ?
    ?
    ?
    /**********************
    DragonBill:
    ***********************/
    ?
    --Congratulation ... Code Length: 344 Bytes. Times: 00:00:08
    create or replace function my_add_months(p_date_string varchar2,
    ???????????????????????????????????????? p_months????? number)
    ? return varchar2
    AS
    ?? C INT := p_date_string;
    ?? H INT := 100;
    ?? Y INT := C/H/H;
    ?? M INT := MOD(C/H, H);
    ?? D INT := MOD(C, H);
    ?? Z INT := Y * 12 + M + p_months;
    ?
    ?? PROCEDURE P
    ?? AS
    ?? BEGIN
    ????? C := 27 + SUBSTR(43434434342 - SIGN(MOD(Y, 16 - 4 * INSTR(Y/H,'.'))), 1 - M, 1);
    ?? END;
    ?
    BEGIN
    ?
    ?? P;
    ?
    ?? M := MOD(Z - 1, 12) + 1;
    ?? Y := (Z - M) / 12;
    ?? Z := C;
    ?
    ?? P;
    ?
    ?? RETURN Y*H*H + M*H + LEAST(D + TRUNC(D/Z) * 3, C);
    END;
    ?
    ?
    --Congratulation ... Code Length: 339 Bytes. Times: 00:00:08
    create or replace function my_add_months(p_date_string varchar2,
    ???????????????????????????????????????? p_months????? number)
    ? return varchar2
    AS
    ?? C INT := p_date_string;
    ?? H INT := 100;
    ?? Y INT := C/H/H;
    ?? M INT := MOD(C/H, H);
    ?? D INT := MOD(C, H);
    ?? Z INT := Y * 12 + M + p_months;
    ?
    ?? PROCEDURE P
    ?? AS
    ?? BEGIN
    ????? C := 27 + SUBSTR(43434434342 - SIGN(MOD(Y, 16 - 4 * INSTR(Y/H,'.'))), 1 - M, 1);
    ?? END;
    ?
    BEGIN
    ?
    ?? P;
    ?
    ?? M := MOD(Z - 1, 12) + 1;
    ?? Y := (Z - M) / 12;
    ?? Z := D/C/2;
    ?
    ?? P;
    ?
    ?? RETURN Y*H*H + M*H + LEAST(D + Z * 3, C);
    END;
    ?
    ?
    /*********************
    判斷閏年: 非百年看后兩位能否被4整除, 百年看前兩位能否被4整除,? 再往前推, 百年能被100整除,
    又 100 = 4 * 25, 故閏百年必能被16整除, 年/100, 能整除的無小數點, 是百年, 不能整除的有小數點,
    湊巧小數點的位置為3, 綜合以上, 故, 非百年 MOD 4 , 百年 MOD 16, 能整除的都是閏年.
    這也就是為什么用 INSTR(Y/H,'.') 而不用 SIGN(MOD(Y, H)) 的原因, 雖然它們的長度是一樣,
    但 12 * {0, 1} 和 4 * {0, 3} 相比, 多了一個Byte
    ?
    現在可以飚到329了
    **********************/
    ?
    --Congratulation ... Code Length: 329 Bytes. Times: 00:00:08
    create or replace function my_add_months(p_date_string varchar2,
    ???????????????????????????????????????? p_months????? number)
    ? return varchar2
    AS
    ?? C INT := p_date_string;
    ?? H INT := 100;
    ?? Y INT := C/H/H;
    ?? M INT := C/H - Y * H;
    ?? D INT := MOD(C, H);
    ?? Z INT := Y * 12 + M + p_months;
    ?
    ?? PROCEDURE P
    ?? AS
    ?? BEGIN
    ????? C := 27 + SUBSTR(43434434342 - SIGN(MOD(Y, 16 - 4 * INSTR(Y/H,'.'))), 1 - M, 1);
    ?? END;
    ?
    BEGIN
    ?
    ?? P;
    ?
    ?? Y := (Z - 7) / 12;
    ?? M := Z - Y * 12;
    ?? Z := D/C/2;
    ?
    ?? P;
    ?
    ?? RETURN Y*H*H + M*H + LEAST(D + Z * 3, C);
    END;
    /

    --Congratulation ... Code Length: 319 Bytes. Times: 00:00:09
    create or replace function my_add_months(p_date_string varchar2,
    ???????????????????????????????????????? p_months????? number)
    ? return varchar2
    AS
    ?? C INT := p_date_string;
    ?? H INT := 100;
    ?? Y INT := C/H/H;
    ?? M INT := C/H - Y * H;
    ?? D INT := C MOD H;
    ?? Z INT := Y * 12 + M + p_months;
    ?
    ?? PROCEDURE P
    ?? AS
    ?? BEGIN
    ????? C := 27 + SUBSTR(43434434341 + 0 ** (Y MOD (4 + 12 * 0 ** (Y MOD H))), 1 - M, 1);
    ?? END;
    ?
    BEGIN
    ?
    ?? P;
    ?
    ?? Y := (Z - 7) / 12;
    ?? M := Z - Y * 12;
    ?? Z := D/C/2;
    ?
    ?? P;
    ?
    ?? RETURN Y * H * H + M * H + LEAST(C, Z || D);
    END;
    /
    ?
    ?




    -The End-

    posted on 2009-05-14 21:42 decode360-3 閱讀(448) 評論(0)  編輯  收藏 所屬分類: SQL Dev
    主站蜘蛛池模板: 无码AV片在线观看免费| 久青草国产免费观看| 嫖丰满老熟妇AAAA片免费看| 亚洲AV无码久久精品蜜桃| 免费网站观看WWW在线观看| 亚洲色精品88色婷婷七月丁香| 人妻巨大乳hd免费看| 亚洲综合最新无码专区| 中文字幕无线码免费人妻| 亚洲精品亚洲人成人网| 无码A级毛片免费视频内谢| 亚洲精品在线电影| 免费国产黄线在线观看| 亚洲AV噜噜一区二区三区| 免费一级毛片在线播放| 久久久久免费视频| 亚洲成人在线网站| 少妇高潮太爽了在线观看免费| 亚洲成a人片在线不卡一二三区| 国产色爽女小说免费看| www免费插插视频| 亚洲av无码不卡| 成人女人A级毛片免费软件| 亚洲av色香蕉一区二区三区| 亚洲精品专区在线观看| 一区二区三区福利视频免费观看| 亚洲av成人综合网| 亚洲v国产v天堂a无码久久| 国产免费一区二区视频| 国产亚洲sss在线播放| 一级毛片直播亚洲| 日韩人妻一区二区三区免费| 亚洲欧洲日产国码久在线| 久久亚洲高清综合| 69式互添免费视频| 免费看黄网站在线看| 亚洲精品网站在线观看你懂的| 国产精品视频免费一区二区三区 | 一级毛片免费在线观看网站| 亚洲av一综合av一区| 天天天欲色欲色WWW免费|