2014-01-17 132 views
2

我在我的數據庫中有3-4個表,我想跟蹤其中的更改。數據庫中多個表的審計歷史記錄

我主要關心更新。

每當更新發生時,我想將先前的條目(值或完整的行)存儲在審計表中。

基本列我在想如下:

AuditId, TableName, PK1, PK2, PK3, PKVal1, PKVal2, PKVal3, UpdateType, PrevEntryJSON 

JSON將是格式:Key:Value和我寧願用它去爲列不斷變化,我想保留的所有值,即使他們不要改變。

其他選項是刪除JSON與100個名稱與不同列(所有表的累積)相同的列。

我想聽聽人們對此的看法。我怎麼能改進它,我可以面對什麼問題?

通過觸發器可能不是最好的方式,但我對它開放。

感謝,

回答

1

我看到一個很有效執行本肚裏如下:

TABLE audit_entry (
    audit_entry_id   INTEGER   PRIMARY KEY, 
    audit_entry_type  VARCHAR2(10) NOT NULL, 
    -- ^^ stores 'INSERT'/'UPDATE' --/'DELETE' 

    table_name    VARCHAR2(30) NOT NULL, 
    -- ^^ stores the name of the table that is changed 

    column_name    VARCHAR2(30) NOT NULL, 
    -- ^^ stores the name of the column that is changed 

    primary_key_id   INTEGER   NOT NULL, 
    -- ^^ Primary key ID to identify the row that is changed 

    -- Below are the actual values that are changed. 
    -- If the changed column is a foreign key ID then 
    -- below columns tell you which is new and which is old 
    old_id     INTEGER, 
    new_id     INTEGER, 

    -- If the changed column is of any other numeric type, 
    -- store the old and new values here. 
    -- Modify the precision and scale of NUMBER as per your 
    -- choice. 
    old_number    NUMBER(18,2), 
    new_number    NUMBER(18,2), 

    -- If the changed column is of date type, with or without 
    -- time information, store it here. 
    old_ts     TIMESTAMP, 
    new_ts     TIMESTAMP, 

    -- If the changed column is of VARCHAR2 type, 
    -- store it here. 
    old_varchar    VARCHAR2(2000), 
    new_varchar    VARCHAR2(2000), 
    ... 
    ... -- Any other columns to store data of other types, 
    ... -- e.g., blob, xmldata, etc. 
    ... 
) 

我們創建一個簡單的順序,給我們新的增量整數值audit_entry_id

CREATE SEQUENCE audit_entry_id_seq; 

audit_entry這樣的表的美麗之處在於您可以存儲有關所有類型DML的信息INSERTUPDATEDELETE在同一個地方。

例如,對於插入,請將old_*列保留爲空,並用您的值填充new_*

對於更新,每當它們被更改時,填充old_*new_*列。

對於刪除,只填寫old_*列並保留new_*爲空。

當然,輸入適當的值爲audit_entry_type。 0)

然後,例如,您有一個表像如下:

TABLE emp (
    empno   INTEGER, 
    ename   VARCHAR2(100) NOT NULL, 
    date_of_birth DATE, 
    salary   NUMBER(18,2) NOT NULL, 
    deptno   INTEGER -- FOREIGN KEY to, say, department 
    ... 
    ... -- Any other columns that you may fancy. 
    ... 
) 

在此表只需創建一個觸發如下:

CREATE OR REPLACE TRIGGER emp_rbiud 
-- rbiud means Row level, Before Insert, Update, Delete 
BEFORE INSERT OR UPDATE OR DELETE 
ON emp 
REFERENCING NEW AS NEW OLD AS OLD 
DECLARE 
    -- any variable declarations that deem fit. 
BEGIN 
    WHEN INSERTING THEN 
     -- Of course, you will insert empno. 
     -- Let's populate other columns. 

     -- As emp.ename is a not null column, 
     -- let's insert the audit entry value directly. 
     INSERT INTO audit_entry(audit_entry_id, 
           audit_entry_type, 
           table_name, 
           column_name, 
           primary_key, 
           new_varchar) 
     VALUES(audit_entry_id_seq.nextval, 
       'INSERT', 
       'EMP', 
       'ENAME', 
       :new.empno, 
       :new.ename); 

     -- Now, as date_of_birth may contain null, we do: 
     IF :new.date_of_birth IS NOT NULL THEN 
      INSERT INTO audit_entry(audit_entry_id, 
            audit_entry_type, 
            table_name, 
            column_name, 
            primary_key, 
            new_ts) 
      VALUES(audit_entry_id_seq.nextval, 
        'INSERT', 
        'EMP', 
        'DATE_OF_BIRTH', 
        :new.empno, 
        :new.date_of_birth); 
     END IF; 

     -- Similarly, code DML statements for auditing other values 
     -- as per your requirements. 

    WHEN UPDATING THEN 
     -- This is a tricky one. 
     -- You must check which columns have been updated before you 
     -- hurry into auditing their information. 

     IF :old.ename != :new.ename THEN 
      INSERT INTO audit_entry(audit_entry_id, 
            audit_entry_type, 
            table_name, 
            column_name, 
            primary_key, 
            old_varchar, 
            new_varchar) 
      VALUES(audit_entry_id_seq.nextval, 
        'INSERT', 
        'EMP', 
        'ENAME', 
        :new.empno, 
        :old.ename, 
        :new.ename); 
     END IF; 

     -- Code further DML statements in similar fashion for other 
     -- columns as per your requirement. 

    WHEN DELETING THEN 
     -- By now you must have got the idea about how to go about this. 
     -- ;0) 
END; 
/

只是一個謹慎的話:是有選擇地選擇你要審覈的表和列,因爲無論如何,你這張表將有大量的行。此表格中的SELECT聲明將比您預期的要慢。

我真的很想看到任何其他類型的實施,因爲這將是一個很好的學習經驗。希望你的問題能得到更多的答案,因爲這是我見過的審計表的最佳實現,我仍在尋找使其更好的方法。

相關問題