Oracle
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Oracle

Kiểm tra lịch sử của nhiều bảng trong cơ sở dữ liệu

Tôi đã thấy việc triển khai điều này rất hiệu quả như sau:

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.
    ...
)

Và chúng tôi tạo một chuỗi đơn giản để cung cấp cho chúng tôi giá trị số nguyên gia tăng mới cho audit_entry_id :

CREATE SEQUENCE audit_entry_id_seq;

Vẻ đẹp của một bảng như audit_entry là bạn có thể lưu trữ thông tin về tất cả các loại DML- INSERT , UPDATEDELETE ở cùng một nơi.

Ví dụ:để chèn, hãy giữ old_* cột rỗng và điền new_* với các giá trị của bạn.

Đối với các bản cập nhật, hãy điền cả old_*new_* bất cứ khi nào chúng được thay đổi.

Để xóa, chỉ cần điền old_* và giữ new_* null.

Và tất nhiên, hãy nhập giá trị thích hợp cho audit_entry_type .; 0)

Sau đó, chẳng hạn, bạn có một bảng như sau:

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.
    ...
)

Chỉ cần tạo một trình kích hoạt trên bảng này như sau:

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;
/

Chỉ một lời cảnh báo:hãy chọn lọc những bảng và cột bạn chọn để kiểm tra, bởi vì dù sao thì bảng này của bạn cũng sẽ có một số lượng lớn các hàng. SELECT các câu lệnh trên bảng này sẽ chậm hơn bạn có thể mong đợi.

Tôi thực sự muốn xem bất kỳ loại triển khai nào khác ở đây, vì đó sẽ là một trải nghiệm học tập tốt. Hy vọng câu hỏi của bạn sẽ nhận được nhiều câu trả lời hơn, vì đây là cách triển khai bảng kiểm toán tốt nhất mà tôi từng thấy và tôi vẫn đang tìm cách để làm cho bảng này tốt hơn.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Số lượng tham số không khớp với số lượng giá trị cho thủ tục được lưu trữ

  2. ORA-27154 / ORA-27146

  3. Cập nhật cột bảng Oracle với số hàng

  4. REGEXP_COUNT bỏ qua phân biệt chữ hoa chữ thường

  5. ORA-06502:PL / SQL:lỗi số hoặc giá trị:bộ đệm chuỗi ký tự quá nhỏ - Đang thực thi bằng giao diện OCI