2012-06-21 138 views
4

我對觸發器相當陌生,所以顯然我在某處做錯了什麼。我正在製作一個報表,它將從原始表中獲取數據。爲了簡單起見,假設有一個表,然後有一個報表。PLSQL觸發器更新另一個表中的字段值

原始表(orig_tab)

CREATE TABLE orig_tab (
PK  NUMBER(8)  not null, 
NAME VARCHAR2(20)   , 
); 

INSERT INTO orig_tab (PK, NAME) VALUES (1, 'AAA'); 
INSERT INTO orig_tab (PK, NAME) VALUES (2, 'BBB'); 
INSERT INTO orig_tab (PK, NAME) VALUES (3, 'CCC'); 

;那麼,報告表(rep_tab)

CREATE TABLE rep_tab (
PK  NUMBER(8)  not null, 
NAME VARCHAR2(20)   , 
); 
從用戶inteface

現在,有人更改記錄2的值,顯然,這應該如何治療作爲插入(因爲此記錄不存在)用於報告表。然後在某個時間之後,值被更改,因此它是報告表的更新情況。

問:我該如何製作這種觸發器?我認爲這是一個合併狀態的情況。

這是我做了什麼:

create or replace trigger vr_reporting_trigger 
after update on orig_tab 
    for each row 
begin 
    MERGE INTO rep_tab d 
    USING (SELECT pk FROM orig_tab) s 
    ON (d.pk = s.pk) 
    WHEN MATCHED THEN 
    UPDATE SET d.pk = s.pk, 
      d.name = s.name 
    WHEN NOT MATCHED THEN 
    INSERT (d.pk, d.name) VALUES (s.pk, s.name); 
end vr_reporting_trigger; 

的任何意見或建議,可以幫助我的數字出來?謝謝。

+0

好的答案規定,凡發現最大的問題(變異表異常(「每一行」觸發不允許從表中選擇),可能要AFTER INSERT OR UPDATE觸發器,還有一些需要考慮處理的角落案例,比如更新到orig_tab.pk(可能不希望在報表中留下「舊」行);或者如果在插入匹配行時報告表中已存在行到orig_tab。 – spencer7593

回答

3

有一些角落情況在以前的答案中沒有處理。

如果匹配的PK已經存在於報表中,當行插入。 (我們通常不會期望發生這種情況,但要考慮如果有人從orig_tab中刪除了一行,然後再次插入它,會發生什麼情況(這是在生產中會出現的那種問題,而不是測試中的問題,在最不合時宜的時候。現在好了計劃吧。)

BEGIN 
    IF inserting THEN 
     -- insure we avoid duplicate key exception with a NOT EXISTS predicate 
     INSERT INTO rep_tab(pk,name) 
     SELECT :new.pk, :new.name FROM DUAL 
     WHERE NOT EXISTS (SELECT 1 FROM rep_tab WHERE pk = :new.pk); 
     -- if row already existed, there's a possibility that name does not match 
     UPDATE rep_tab t SET t.name = :new.name 
     WHERE t.pk = :new.pk; 
     -- could improve efficiency of update by checking if update is actually 
     -- needed using a nullsafe comparison (t.name <=> :new.name); 
    ELSIF updating THEN 
     -- handle updates to pk value (note: the row to be updated may not exist 
     -- so we need to fallthru to the merge) 
     IF :new.pk <> :old.pk THEN 
     UPDATE rep_tab t 
      SET t.pk = :new.pk 
       , t.name = :new.name 
      WHERE t.pk = :old.pk ; 
     END IF; 
     MERGE INTO rep_tab d 
     USING DUAL ON (d.pk = :old.pk) 
     WHEN MATCHED THEN 
     UPDATE SET d.name = :new.name 
     WHEN NOT MATCHED THEN 
     INSERT (d.pk,d.name) VALUES (:new.pk,:new.name); 
    END IF; 
END; 
3

MERGE語句聽起來像一個計劃,只是因爲你提到這是一個AFTER UPDATE觸發器,而不是一個AFTER INSERT觸發器觸發不會當你在做第一次插入點火。

此外,SELECT pk FROM orig_tab將導致Mutating table problem

更好的方式是定義一個AFTER INSERT或UPDATE觸發器,與INSERT/UPDATING關鍵字結合起來,以處理插入/更新&使用:new/:old分別處理新數據&舊數據。

CREATE OR replace TRIGGER vr_reporting_trigger 
    AFTER INSERT OR UPDATE ON orig_tab 
    FOR EACH ROW 
BEGIN 
    IF inserting THEN 
     INSERT INTO rep_tab 
        (pk, 
        name) 
     VALUES  (:NEW.pk, 
        :NEW.name); 
    ELSIF updating THEN 
     UPDATE rep_tab r 
     SET name = :NEW.name 
     WHERE r.pk = :old.pk; 
    END IF; 
END vr_reporting_trigger; 
+0

感謝Sathya的迴應。我可以在更新中看到一些小問題:如果記錄在orig_tab中更新並且在rep_tab中沒有對應的記錄,則此邏輯可能不起作用 – Jaanna

+0

@Jaanna如果記錄不存在,您可以檢查記錄的存在並插入記錄 – Sathya

+0

elsif如果rep_tab.pk <>:old.pk,則更新 然後 INSERT INTO rep_tab(pk,name)VALUES(:NEW.pk,:NEW.name); else UPDATE rep_tab r SET name =:NEW.name WHERE r.pk =:old.pk; endif; 不起作用 – Jaanna

1

這是Sathya AnswerJaanna被問及如果記錄在orrig_tab更新的延伸,在rep_tab沒有相應的記錄,則下面的邏輯將滿足下面,請您及時請求不同意這個答案評判我此解決方案屬於Sathya

CREATE OR replace TRIGGER vr_reporting_trigger 
    AFTER INSERT OR UPDATE ON orig_tab 
    FOR EACH ROW 
BEGIN 
    IF inserting THEN 
     INSERT INTO rep_tab 
        (pk, 
        name) 
     VALUES  (:NEW.pk, 
        :NEW.name); 
    ELSIF updating THEN 
     MERGE INTO rep_tab d 
      USING DUAL 
     ON (d.pk =:OLD.pk) 
     WHEN MATCHED THEN 
     UPDATE SET d.name = :OLD.name    
     WHEN NOT MATCHED THEN 
     INSERT (d.pk,d.name) VALUES (:OLD.PK,:NEW.PK); 
    END IF; 
END vr_reporting_trigger; 
+0

@Sathya:請驗證我的除了你的解決方案,謝謝 –

+0

@Guarav:在INSERT(當不匹配),不應該是'VALUES(:new.PK,:new.name)'?而在更新(匹配時)應該不是'd.name =:new.name'?這是否處理pk列的值更新時的情況? – spencer7593

+0

@GauravSoni您的評論應該在我的回答中,我沒有收到通知。另外,不要將分號添加到名稱中。話雖如此,這似乎很好。 – Sathya

相關問題