2015年10月2日 星期五

oracle function 日期 流水號

這次要用 oracle function 來實作 日期流水號~(每天從1開始跑)
以前都習慣用AP實作,不過因為這邊是多台又同時,會造成號碼重覆的問題~
聽說改了幾次寫法還是衝突,最後只好來試試...唯一的瓶頸-->就是那台DB...

我不太知道英文的關鍵字要怎麼下~中翻英去找,結果都蠻慘的~
不過用中文的話~打「oracle 日期 流水號」...就可以看到不少的參考~

不過我說是參考...因為照貼結果感覺都很慘就是XD...

這次的解法,是用DB 開 table 來記(不是做DB 的流水號)
因為覺得去reset seq 是一件很蠢的事情~感覺上也不符合seq的精神....

table,主要的欄位就是「日期」,跟「現在號碼」,為了通用,再多加個「流水號類別 」...
原理就是~指定類別,若日期內有號碼,就把號碼+1丟出。若table沒有那個日期,就丟1,insert一筆新的日期,和號碼1進去。
(理論上比較好的想法是降子,不過後來因為 ooxx的考量...我是不用insert,而是日期不同,就把原本的資料蓋成 【新的日期】,跟把號碼變成1。變形後可以減少筆數~當然是前端 AP的日期不能亂丟就是~若在跨日其實是會出事的XD,不過要是這事情不會發生就算了~)

----修正版~
後來想一想,還是改個寫法~先撈值出來看一下日期再做處理~

CREATE OR REPLACE FUNCTION FN_XXXX_SEQ(P_CTYPE IN VARCHAR2, P_DT IN VARCHAR2)
  RETURN VARCHAR2 IS V_SEQ VARCHAR2(10);
 
BEGIN
  BEGIN
    Select l.DT INTO P_DT From OWNER.TB_AAA l where l.TYPE = P_TYPE ;  
    if P_DT is not null and P_DT >= to_char(SYSDATE,'YYYYMMDD') then 
        UPDATE OWNER.TB_AAA S
           SET S.SN = LPAD(to_number(S.VALUE2)+1, 4, '0')
        WHERE S.TYPE = P_CTYPE
         RETURNING substr(S.DT, 3) || S.SN INTO V_SEQ;
   else
         UPDATE OWNER.TB_AAA S
         SET S.SN = '0001',
             S.DT = to_char(SYSDATE,'YYYYMMDD')
       WHERE S.TYPE = P_CTYPE
       RETURNING substr(S.DT, 3) || S.SN INTO V_SEQ;
    end if;
 
  END;

  COMMIT;
 
  RETURN V_SEQ;
END FN_XXXX_SEQ;

function實作上,基本上就是,你來我就先update 一次,然後把 序號 給到 V_SEQ內。
P_DT會先暫存 DB目前的日期(想做個Varible,一直GG..就算了Orz..),然後看是要用舊的資料,還是改新值給1...(日期若比資料庫小的,一律就以資料庫的時間為主~)

然後都寫成 function了,那就組好流水號格式送出去,AP端不再加工了~

雖說 oracle 對數字format 也有其他的寫法,不過 LPAD,好像比較正確~

另外,原本是要採用 EXCEPTION的判斷寫入(感覺得這個才比較正統)
但是~不知道為什麼~就是一直都掉不進  NO_DATA_FOUND
https://docs.oracle.com/cd/B10500_01/appdev.920/a96624/07_errs.htm
換了好幾個Exception也都不是...

事後,寫了個多Thread,模擬壓測的程式狂取號~似乎寫到function內,沒有重覆號的問題~原本想說不行就要DB lock(但是那個太危險了),但目前看起來是OK的樣子就是~

沒有留言: