2010-08-09 99 views
2

我正在開發一個系統來跟蹤項目的歷史。有3個主表:項目,任務和客戶,然後是3個歷史表。我在項目表上有以下觸發器。oracle和創建歷史

CREATE OR REPLACE TRIGGER mySchema.trg_projectHistory 
BEFORE UPDATE OR DELETE 
ON mySchema.projects REFERENCING NEW AS New OLD AS Old 
FOR EACH ROW 
declare tmpVersion number; 
BEGIN 
    select myPackage.GETPROJECTVERSION(:OLD.project_ID) into tmpVersion from dual; 

    INSERT INTO mySchema.projectHistiry 
    (project_ID, ..., version) 
    VALUES 
    (:OLD.project_ID, 
    ... 
    tmpVersion 
    ); 

EXCEPTION 
WHEN OTHERS THEN 
    -- Consider logging the error and then re-raise 
    RAISE; 
END ; 
/

我有三個觸發器爲我的每個表(項目,任務,客戶端)。

以下是挑戰:並非所有事情都在同一時間發生變化。例如,有人可以更新某個任務的成本。在這種情況下,只有一個觸發器觸發,並且我有一個插入。即使在項目和客戶表中沒有任何更改,我想一次將一條記錄插入到3個歷史記錄表中。

另外,如果有人更改項目的end_date,成本,並說選擇另一個客戶端會怎麼樣。現在,我有三個觸發器同時觸發。只有在這種情況下,我纔會在我的三張歷史記錄表中插入一條記錄。 (我想要的)

如果我修改觸發器插入到第一個示例的3個表中,那麼當第二個示例發生時,我將有9個插入。

不太清楚如何解決這個問題。任何幫助?

回答

0

從您的描述中可以看出,一旦任何原始行發生更改,您將捕獲每個歷史記錄行的生效日期和結束日期。

例如, Project_hist表將具有eff_date和exp_date,它具有給定項目的開始日期和結束日期。項目表只會有一個生效日期。 (因爲它是活躍的項目)。

我不明白爲什麼要在只更新一個表值時爲所有三個歷史記錄表插入行。您可以根據自己當前的邏輯,根據需要獲取詳細信息(截至給定日期)。 (在已更新的表格的歷史記錄表格中插入舊行)。

+0

是真實的,但是我面臨的另一個挑戰是現在有任務歷史記錄,但沒有項目/客戶歷史記錄。我必須找出一個連接:如果x_history中沒有任何內容,請從x獲取它。 – CFNinja 2010-08-09 19:10:56

+0

那麼,在這種情況下,你可以嘗試在歷史表中同時使用活動版本和非活動版本嗎?這種方法的缺點是,在每次更新操作表中的當前記錄後,您需要更新歷史記錄中的最新記錄,然後插入新記錄。 – 2010-08-09 19:41:03

+0

歷史記錄表僅包含非活動版本。對任何主表的任何更新/刪除都將創建不活動的歷史版本。 我如何做後者? 如果x_history中沒有任何內容,請從x獲取它。 – CFNinja 2010-08-09 20:45:56

2

對我來說,聽起來好像你想要對任何一個表進行更改時創建的三個表的事務級快照。

在三個表中的每一個上都有一個行級別的觸發器,它們調用帶有項目ID和可選的客戶機/任務ID的單個打包過程。

打包過程會在所有三個歷史記錄表中插入相關的項目,客戶端和任務,其中沒有該密鑰和事務的歷史記錄(即,您不需要重複項)。談到後者,你有幾個選擇。你可以使用一個唯一的約束和一個BULK選擇和插入與FORALL/SAVE EXCEPTIONS,DML錯誤記錄(EXCEPTIONS INTO)或INSERT ... SELECT ... WHERE NOT EXISTS ...

你確實需要跟蹤您的交易。我猜這是你用myPackage.GETPROJECTVERSION所做的。這裏的技巧是隻有當你有一個新的事務時才增加版本。如果當你得到一個新的版本號,你將它保存在一個pacakge級別變量中,你可以很容易地判斷你的會話是否已經有一個版本號。

如果您的會話要運行多個事務,那麼如果它是前一個事務的一部分,則需要「清除」會話級版本號。如果您獲得DBMS_TRANSACTION.LOCAL_TRANSACTION_ID並將其存儲在程序包/會話級別,則可以確定您是在新事務中還是在同一事務中。

+0

+1用於診斷問題背後的用例 – APC 2010-08-10 03:25:33

+0

我想你會想爲同一事務中的後續更改執行「合併」。如果你使用'not exists',你最終會得到一個快照,其中包含對一個表的初始更改並忽略另外兩個(以及對同一事務中第一個表的進一步更改)。 – Allan 2010-08-10 21:09:33

0

替代答案。 查看Total Recall/Flashback Archive 您可以將保留時間設置爲10年,並使用簡單的AS OF TIMESTAMP來獲取任何特定時間戳的數據。

雖然不確定。每天或每週保留一次可能更容易,然後使用VERSIONS BETWEEN語法挑選出較早版本的單獨計劃作業,並將它們存儲在歷史記錄表中。

+0

如果這些牌照有錢的話,Total Recall絕對是最優雅的解決方案。 – APC 2010-08-10 03:22:21