Decode360's Blog

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

            BlogJava :: 首頁 :: 新隨筆 :: 聯系 ::  :: 管理 ::
            397 隨筆 :: 33 文章 :: 29 評論 :: 0 Trackbacks
          最小源代碼擂臺[ITPub]
          ?
          ??? 很久以前看過的一個帖子,今天又翻到了,覺得還挺有意思的,摘錄一下:
          ??? 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;
          /
          ?
          ?
          posted on 2009-05-14 21:42 decode360 閱讀(289) 評論(0)  編輯  收藏 所屬分類: 06.PLSQL
          主站蜘蛛池模板: 精河县| 江北区| 自治县| 射阳县| 保德县| 乌苏市| 西畴县| 读书| 石门县| 曲松县| 东城区| 上蔡县| 鹤峰县| 隆子县| 斗六市| 丰城市| 桦川县| 阿勒泰市| 磐石市| 新绛县| 仁化县| 聊城市| 兴城市| 新河县| 克什克腾旗| 庆安县| 西乡县| 佛冈县| 灵璧县| 肇州县| 绥德县| 武宁县| 福安市| 砚山县| 买车| 新宁县| 焉耆| 西青区| 扶沟县| 四会市| 中卫市|