sql >> データベース >  >> RDS >> Oracle

データベース内の複数のテーブルの監査履歴

    私はこれの非常に効果的な実装を見てきました。これは次のようになります。

    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に関する情報を保存できるということです-INSERTUPDATE およびDELETE 同じ場所で。

    たとえば、挿入の場合は、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 このテーブルのステートメントは、予想よりも遅くなります。

    良い学習体験になるので、ここで他の種類の実装を見てみたいと思います。これは私が見た監査テーブルの最良の実装であり、それを改善する方法をまだ探しているので、あなたの質問がより多くの答えを得ることを願っています。




    1. node.js同期mysqlクエリ

    2. Spring DataのJPAリポジトリを使用したFindByUUID()

    3. Knex.jsは、次の4つのクエリでセッションの再利用を強制します

    4. MySQLのSUM結果のデータ型