2012-08-29 99 views
4

我們有以下要求變異表的問題複合主鍵version, id當TRIGGER需要選擇在同一個表中插入行

------------------------------------ 
version id  col1 coll2 active 
------------------------------------ 
1  123 'A' 'B'  'N' 
2  123 'C' 'D'  'Y' 
1  124 'E' 'F'  'Y' 

現在對於任何插入和更新上table1一個給定的id,應創建一個新行,並具有以下屬性(由觸發器派生):

  1. Version應由1給出id
  2. 最當前行應成爲活性被遞增(active列被設置爲Y

例如

INSERT INTO table1(id, col1, col2) VALUES (123, 'X', 'Y'); 

------------------------------------ 
version id  col1 coll2 active 
------------------------------------ 
1  123 'A' 'B'  'N' 
2  123 'C' 'D'  'N' 
3  123 'X' 'Y'  'Y' 
1  124 'E' 'F'  'Y' 

第三行是爲變爲無效ID 124創建

UPDATE table1 SET col1 = 'F' WHERE id = 124; 

------------------------------------ 
version id  col1 coll2 active 
------------------------------------ 
1  123 'A' 'B'  'N' 
2  123 'C' 'D'  'N' 
3  123 'X' 'Y'  'Y' 
1  124 'E' 'F'  'N' 
2  124 'F' 'F'  'Y' 

創建最後一行

DELETE FROM dbo.table1 WHERE id = 124; 

------------------------------------ 
version id  col1 coll2 active 
------------------------------------ 
1  123 'A' 'B'  'N' 
2  123 'C' 'D'  'N' 
3  123 'X' 'Y'  'Y' 
1  124 'E' 'F'  'N' 
2  124 'F' 'F'  'N' 

所有行。

這似乎是一個建模問題,但我們被授權使用TABLE1和支持觸發器來提供此功能。

我們無法繞過修改表問題,因爲我們需要select max(version) 然後插入到同一張表中,任何人都可以請建議一種解決方法嗎?

+1

的變異表的問題是隻在這裏需要解決的兩個問題之一。另一個問題是,應該怎樣解決方案處理大約在同一時間更新表會。每次會議將不會看到其他會話未提交的修改,使之不以某種方式推出系列化任何基於觸發器的解決方案可能會是錯的。 –

回答

5

我不喜歡這個數據庫的設計,這是可怕的,但你說你是堅持了下來。如何使用帶INSTEAD OF觸發器的視圖?

1)重命名錶例如TABLE1_BASE

2)創建視圖TABLE1如SELECT * FROM TABLE1_BASE

3)添加INSTEAD OF觸發器是這樣的:

create trigger table1_io 
instead of insert or update or delete on table1 
for each row 
begin 
    if inserting or updating then 
     update table1_base 
     set active = 'N' 
     where id = :new.id 
     and active = 'y'; 

     insert into table1_base...; 
    elsif deleting then 
     update table1_base 
     set active = 'N' 
     where id = :old.id 
     and active = 'y'; 
    end if; 
end; 

(類似的東西)

+1

你需要在一個序列點增加的情況下,兩會插入/更新大約在同一時間的表。 –

4

正如你所說這是一個建模問題,並且突變表錯誤通常表明有更好的方法來實現這一點。

有一些方法可以解決這個問題,但它們都不是最佳實踐,必須權衡增加的複雜性與業務邏輯/表的重要性。如果這是一個關鍵表,你是否真的想在複雜的邏輯上使用簡單的插入?

方法1 將包中的更新放在包過程中。從調用此過程的觸發器中運行作業。這意味着你現在有兩個交易:原始插入和後續。

方法2(類似於1) 創建封裝要進行的變更,先進的隊列和對象類型。在插入期間添加到隊列中。出隊對象並根據需要應用更改。你的情況:立即。方法1和2的優點是,由於後續清理,初始事務永遠不會停止。

方法3(的作品,但不是最好的做法,由於複雜性) 您需要兩個觸發器:在表中插入後,在桌子上,之後插入的每一行

兩個觸發器調用一個包封裝你的邏輯,這將是這個樣子

CREATE OR REPLACE PACKAGE BODY XYZ AS 
    TYPE t_template_rec 
    IS 
     RECORD (case_id  NUMBER (10), objective_id NUMBER (10)); 

    TYPE t_template_table IS TABLE OF t_template_rec; 

    g_change_table t_template_table 
     := t_template_table() ; 

    TYPE t_deliv_rec IS RECORD (case_id NUMBER (10), stage_id NUMBER (10)); 

    TYPE t_deliv_table IS TABLE OF t_deliv_rec; 

    g_deliv_table       t_deliv_table := t_deliv_table(); 

表級觸發器通過一個主鍵和數據到該過程

PROCEDURE CHECK_FOR_TEMPLATES (case_id_in  IN NUMBER, 
            objective_in IN NUMBER) 
    IS 

    BEGIN 

     g_change_table.EXTEND; 
     g_change_table (g_change_table.LAST).case_id := case_id_in; 
     g_change_table (g_change_table.LAST).objective_id := objective_in; 
    END CHECK_FOR_TEMPLATES; 

行級觸發器在同一個包

PROCEDURE ADD_TEMPLATES_ON_STATEMENT 
    IS 

     v_count   NUMBER (10); 
     v_case_id  NUMBER (10); 
     v_objective_id NUMBER (10); 
    BEGIN 
     FOR i IN g_change_table.FIRST .. g_change_table.LAST 
     LOOP 
     SELECT COUNT (*) 
      INTO v_count 
      FROM XYZ.DELIVERABLE_TEMPLATE dt 
      WHERE DT.INITIATIVE_OBJECTIVE_ID = 
        g_change_table (i).objective_id; 
     --check if there is any work to be done 
     IF v_count > 0 
     THEN 
      v_case_id := g_change_table (i).case_id; 
      v_objective_id := g_change_table (i).objective_id; 
      --do some work here 
     END IF; 
     END LOOP; 

     g_change_table.delete; 
    END ADD_TEMPLATES_ON_STATEMENT; 

爲清楚起見,我已刪除的意見/調試/斷言調用不同的過程。我正在使用方法#3,一旦我得到它的工作,它工作正常,但如果我不得不回去並在該表上實施更多的業務邏輯,我會小心處理它。

相關問題