审核数据库中多个表的历史记录

我的数据库中有3-4个表,我想跟踪它们的变化。

我主要关注更新。

每当发生更新时,我想在审计表中存储先前的条目(值或完整行)。

我想到的基本专栏如下:

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

JSON将采用以下格式: Key:Value ,我更喜欢随着列的不断变化,我希望保留所有值,即使它们没有变化。

其他选项是删除带有100个列的JSON,这些列的名称与不同的列相同(所有表的累计)。

我想听听别人对此的看法。 我怎么能改进它以及我可以面对哪些问题?

通过触发器可能不是更好的方式,但我对此持开放态度。

谢谢,

我已经看到了一个非常有效的实现,如下所示:

 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, ... -- eg, blob, xmldata, etc. ... ) 

我们创建一个简单的序列,为audit_entry_id提供新的增量整数值:

 CREATE SEQUENCE audit_entry_id_seq; 

audit_entry这样的表的美妙之audit_entry在于,您可以在同一个地方存储有关所有类型的DML- INSERTUPDATEDELETE的信息。

例如,对于insert,将old_*列保留为null并使用您的值填充new_*

对于更新,只要更改old_*new_*列,就会填充它们。

对于删除,只需填充old_*列并保持new_* null。

当然,为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语句将比您预期的要慢。

我真的很想看到任何其他类型的实现,因为这将是一个很好的学习经验。 希望你的问题得到更多的答案,因为这是我见过的审计表的最佳实现,我仍然在寻找使其更好的方法。