Ich habe eine sehr effektive Implementierung davon gesehen, die wie folgt abläuft:
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.
...
)
Und wir erstellen eine einfache Sequenz, um uns einen neuen inkrementellen ganzzahligen Wert für audit_entry_id
zu geben :
CREATE SEQUENCE audit_entry_id_seq;
Die Schönheit einer Tabelle wie audit_entry
ist, dass Sie Informationen über alle Arten von DMLs speichern können - INSERT
, UPDATE
und DELETE
an der gleichen Stelle.
Behalten Sie z. B. für insert den old_*
bei Spalten null und füllen Sie new_*
mit deinen Werten.
Füllen Sie für Updates sowohl old_*
und new_*
Spalten, wenn sie geändert werden.
Geben Sie zum Löschen einfach old_*
ein Spalten und behalten Sie new_*
bei null.
Geben Sie natürlich den entsprechenden Wert für audit_entry_type
ein .;0)
Dann haben Sie zum Beispiel eine Tabelle wie folgt:
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.
...
)
Erstellen Sie einfach wie folgt einen Trigger für diese Tabelle:
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;
/
Nur ein Wort der Vorsicht:Seien Sie wählerisch bei der Auswahl der zu prüfenden Tabellen und Spalten, da diese Tabelle ohnehin eine große Anzahl von Zeilen enthalten wird. SELECT
Anweisungen in dieser Tabelle werden langsamer sein, als Sie vielleicht erwarten.
Ich würde wirklich gerne jede andere Art der Implementierung hier sehen, da es eine gute Lernerfahrung wäre. Ich hoffe, dass Ihre Frage mehr Antworten erhält, da dies die beste Implementierung einer Audit-Tabelle ist, die ich gesehen habe, und ich immer noch nach Möglichkeiten suche, sie zu verbessern.