2012-02-14 198 views
1

當表中有列的任何列已更新時,我想插入一行到歷史記錄表中。PL SQL觸發器在列更新時插入歷史記錄

我只是想捕捉列名,舊值和新值。

我希望這個觸發器儘可能重複使用,因爲我要在其他表上使用相同的概念。

我熟悉觸發器以及如何捕獲一列上的更新。我正在專門查找如何編寫一個觸發器,該記錄將一條記錄插入歷史記錄表中,用於任何列,該列在歷史記錄表的相應表中得到更新。

編輯1
我已經指出NOWHERE在我的職位,我在尋找源代碼,這樣任何人恥辱,downvotes我,認爲我在找那個。你可以查看我以前的問題/答案,看看我不是在尋找「免費源代碼」。

正如我在我原來的問題所述,我正在尋找如何來寫這個。我已經檢查了http://plsql-tutorial.com/plsql-triggers.htm,並且有一個代碼塊顯示瞭如何在ONE列更新時寫入觸發器。我想,也許有人會知道如何爲我提出的場景提供更通用的觸發器。

+1

對。想知道我每小時收費多少? SO不是免費的編碼服務。你試過什麼了? – 2012-02-14 17:31:41

+0

@Adrian - 在這裏尋找一個小方向...我的問題從來沒有說明我正在尋找任何人爲我寫代碼...... – 2012-02-14 17:36:14

+0

夠公平的。問題在於你的問題聽起來就像我正在閱讀的Spec doc文件。你必須給我們一些東西。你有沒有辦法?你有沒有研究過這是否可能?你研究過RDBMS(oracle)是否已經提供了這個功能嗎? – 2012-02-14 17:39:48

回答

9

假設一個常規表格而不是一個對象表格,你沒有很多選項。你觸發必須是形式的東西

CREATE OR REPLACE TRIGGER trigger_name 
    AFTER UPDATE ON table_name 
    FOR EACH ROW 
BEGIN 
    IF(UPDATING('COLUMN1')) 
    THEN 
    INSERT INTO log_table(column_name, column_value) 
     VALUES('COLUMN1', :new.column1); 
    END IF; 

    IF(UPDATING('COLUMN2')) 
    THEN 
    INSERT INTO log_table(column_name, column_value) 
     VALUES('COLUMN2', :new.column2); 
    END IF; 

    <<repeat for all columns>> 
END; 

你可以獲取COLUMN1COLUMN2,...從數據字典(USER_TAB_COLS),而不是COLUMN<<n>>字符串硬編碼他們,但你還是要硬編碼對:new僞記錄中列的引用。

你可能會寫一段代碼,通過查詢數據字典生成上述觸發(USER_TAB_COLSALL_TAB_COLS最有可能的),建設有DDL語句的字符串,然後做一個EXECUTE IMMEDIATE執行DDL語句。您隨後必須在任何時候將新列添加到任何表以重新創建該列的觸發器時調用此腳本。編寫和調試這種類型的DDL代碼非常繁瑣,但在技術上並不是特別具有挑戰性。但很少有人值得這樣做,因爲有人不可避免地會添加一個新列並忘記重新運行該腳本,或者某人需要修改觸發器以執行一些額外的工作,並且手動更新觸發器比修改和測試生成的腳本更容易觸發器。

但是,更普遍的是,我會質疑以這種方式存儲數據的智慧。在歷史記錄表中爲修改的每一行的每一列存儲一行使得歷史數據非常具有挑戰性。如果有人想知道特定行在特定時間點處於什麼狀態,則必須將歷史表N次加入其中,其中N是該時間點表中的列數。這會非常低效,很快就會讓人們避免嘗試使用歷史數據,因爲他們無法在合理的時間內對其做有用的事情,而不會讓他們失望。使用具有相同的活動表格列的歷史記錄表(在跟蹤日期等方面添加了一些內容)以及在每次更新行時在歷史表中插入一行是比較有效的。這將消耗更多的空間,但它通常更容易使用。

而Oracle有多種方式來審計數據變更 - 您可以使用AUDIT DML,您可以使用細粒度審計(FGA),您可以使用Workspace Manager,也可以使用Oracle Total Recall。如果您正在尋找比編寫自己的觸發器代碼更大的靈活性,我強烈建議您研究這些本質上更加自動化的其他技術,而不是嘗試開發自己的架構。

+0

夢幻般的答案和方向 - 謝謝。 – 2012-02-14 18:01:36

+0

大答案像往常一樣 – tbone 2012-02-14 18:07:46

4

您可能會將歷史記錄表設置爲與主表格相同的+日期和類型字段。由於新值位於主表中,因此只需捕獲舊值。 ,

create or replace trigger "MY_TRIGGER" 
before update or delete 
on MY_TABLE referencing new as new old as old 
for each row 
declare 
    l_dml_type varchar2(10); 
begin 
if (updating) then 
    l_dml_type := 'UPD'; 
else 
    l_dml_type := 'DEL'; 
end if; 

insert into MY_TABLE_HIST 
(
col1, 
col2, 
col3, 
dml_type, 
dml_date 
) 
values 
(
:old.col1, 
:old.col2, 
:old.col3, 
l_dml_type, 
sysdate 
); 
end; 
/
+0

+1 - 感謝這篇文章 - 我可能最終會朝着這個方向,因爲它的簡潔明瞭 – 2012-02-14 18:23:26

+3

我能得到Justin的點,然後;-) – tbone 2012-02-14 18:24:12

1

作爲一個說明根據您的設計,如果空間是一個限制,您可以創建將跟蹤的方式,你所追求的變化的看法,:

嘗試這種(未經測試)並只顯示當時的記錄。

+1

這似乎是一個註釋,下應張貼這樣的題。在評論權限之前,您需要更多地參與社區以獲得一些聲譽。歡迎來到SO! – VKen 2012-10-10 19:21:00