Oracle觸發器原來也可以這麼玩

1.前言

項目驅動學習是一件行之有效的方式。最近項目中確實遇到了很多問題。當然按照之前的處理方式也未嘗不可,不過想到以後的維護感覺還是想辦法在改進一下吧。這次,我們主要討論一下Oracle觸發器在實際工作中的應用。同時借組SqlDevelop工具分享一下編寫觸發器過程的調式技巧(之前一編譯就出現編譯警告就無從下手)。當然,我還是初次接觸調試,方法雖不盡人意,但是也不失一種方法。

2.業務描述

對於有父子及結構的數據中,層次化編碼是一種很好的數據處理方式。拿身份證舉例,他的每一位都代表有特殊的含義。比如130開頭屬於河北,110開頭的屬於北京等等。如果我們要查詢一張表中北京人員,我們就可以使用Sql語句:

SELECT * FROM STUDENT WHERE CARD_ID LIKE '110%';

如果我們要查詢張家口的人員呢,觸類旁通,

SELECT * FROM STUDENT WHERE CARD_ID LIKE '1307%';

通過以上實例,我們發現不需要對張家口下屬的縣,縣下屬的鄉進行遍歷查找,性能提升了很多(這裏有讀者可能會說prior關鍵字可以實現這個功能。然而通過對比,我相信誰都知道查詢那個簡單。

那麼問題來了,我們怎麼去維護這個字段呢?我們可以有兩種方式:

1.在每次插入更新表的時候查詢數據庫計算java代碼處理。這樣處理的好處就是我們都熟悉代碼,只要邏輯屢清楚了,實現不成問題。但是他存在一下幾個問題:

1)多次java代碼查詢數據庫,會影響數據庫性能;

2)我們沒法辦做到做的全面。如果我們對於插入或者更新的Sql遺漏了就會出現問題。同時如果後期與其他系統集成,開發人員不知道這個字段的處理邏輯或者遺忘,那將是一件很糟糕的事。

一句話概率,性能欠佳,維護困難。

2.通過Oracle觸發器實現層次化編碼設計。就是不管java什麼時候進行對錶進行update或者insert之前都要執行此處的觸發器,也就不怕無限制的增加sql語句了。然而,這個回的人不多,實現難度大。

經過我們商量,決定還是先去嘗試方法二:Oracle觸發器。如果在項目上線之前還沒有解決思路,我們暫時按照思路一處理。

對於我們的具體邏輯是這樣的,我們對組織機構進行層次化編碼設計。每一個層級爲4位編碼。也就是說第一層級爲4位編碼,第二層爲8位編碼,依次類推(不要吐槽爲什麼設置這麼長)。

在組織機構中我們主要有三個字段,【org_id,parent_id,lev_id】,其中org_id爲組織的流水id,parent_id爲原有的父級節點ID(我們不能刪掉他,否則會出現異常);lev_id,層級結構id,也就是我們說的表示層級結構的ID(這個字段是我們後期增加的,並不影響原有的代碼邏輯。

3.代碼邏輯

1)在原表中查詢父級id(parent_id)爲當前插入數據的parent_id,這裏找到最大的一個。

2)如果查詢結果爲null,則在原表中id=當前插入數據的parent_id,這裏應該只有一個值。此時如果滿足,則在查詢的值結尾追加【0001】;如果仍爲null,那值爲0001.

3)如果步驟一中存在值,則在查詢的值基礎上+1。

4)將處理後的值更新到數據表中。

4.代碼展示

CREATE OR REPLACE TRIGGER TAG_SM_ORGANIZATION
  BEFORE INSERT OR UPDATE ON SM_ORGANIZATION
  FOR EACH ROW
  DECLARE
    P_IDS INT;
    P_IDS_STR VARCHAR2(100);
    P_LEN INT;
  BEGIN
    SELECT (TO_NUMBER(MAX(PARENT_IDS))+1) INTO P_IDS FROM SM_ORGANIZATION WHERE PARENT_ID = :NEW.PARENT_ID;
    IF P_IDS IS NULL THEN
      BEGIN
        SELECT MAX(PARENT_IDS) || '0001' INTO P_IDS_STR FROM SM_ORGANIZATION WHERE ORGA_ID = :NEW.PARENT_ID;
      END;
    ELSE
      BEGIN
        --計算新編號總長度
        P_IDS_STR := TO_CHAR(P_IDS);
        P_LEN := LENGTH(P_IDS_STR);
        P_LEN := CEIL(P_LEN/4) * 4;
        --位數不足左側補0
        P_IDS_STR := LPAD(P_IDS_STR,P_LEN,'0');
      END;
    END IF;
    --更新新值
    :NEW.LEV_ID := P_IDS_STR;
  END;

5.調式技巧

5.1 中間數據輸出

1)在代碼中加入以下語句:DBMS_OUTPUT.PUT_LINE(P_IDS);其中p_IDS爲要輸出的值;

2)打開日誌輸出開關

5.2 執行完畢,但有警告

1)打開左側列表->觸發器,我們發現剛纔創建的觸發器有紅叉。

2)選中我們創建的觸發器,右擊編輯

3)此時我們發現錯誤的地方,在倒數第二行少了一個分號。

通過以上步驟我們可以快速定位錯誤,加快觸發器編譯步驟。

好了,以上就是我給大家分享的內容,希望大家喜歡。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章