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

Oracleトリガーを使用した50列の監査

    elseに関する差し迫った問題 常に呼び出されるのは、インデックス変数 rを使用しているためです。 関連する列名を検索するのではなく、直接:

    for r in v_tab_col_nt.first..v_tab_col_nt.last
    loop
        if updating(v_tab_col_nt(r)) then
            insert into data_table values(1,'i am updating '||v_tab_col_nt(r));
        else
            insert into data_table values(2,'i am inserting '||v_tab_col_nt(r));
        end if;
    end loop;
    

    また、 idのみを表示しています テーブル作成の列なので、 r 2です 、常に nameを挿入していると表示されます 、更新しないでください。さらに重要なのは、 nameがあった場合です。 列であり、特定の idに対してのみ更新されていました 、このコードは idを表示します 変更されていないときに挿入するように。挿入/更新を別々のブロックに分割する必要があります:

    if updating then
        for r in v_tab_col_nt.first..v_tab_col_nt.last loop
            if updating(v_tab_col_nt(r)) then
                insert into data_table values(1,'i am updating '||v_tab_col_nt(r));
            end if;
        end loop;
    else /* inserting */
        for r in v_tab_col_nt.first..v_tab_col_nt.last loop
            insert into data_table values(2,'i am inserting '||v_tab_col_nt(r));
        end loop;
    end if;
    

    これでも、 nameを挿入していると表示されます 列が存在しない場合でも、それは間違いだと思います。 user_tab_columnsから名前のリストにデータを入力しようとしていると思います。 とにかく、本当に動的にしようとしたいのなら。

    私は、個々の列ではなく、行全体のコピーを取得する監査テーブルを使用したほうがよいと思われる他のユーザー(少なくとも一部)に同意します。あなたの異議は、どの列が変更されたかを個別にリストすることの複雑さのようです。列ごとのデータが必要なときに監査テーブルのピボットを解除することで、少しの作業でこの情報を取得できます。例:

    create table temp12(id number, col1 number, col2 number, col3 number);
    create table temp12_audit(id number, col1 number, col2 number, col3 number,
        action char(1), when timestamp);
    
    create or replace trigger temp12_trig
    before update or insert on temp12
    for each row
    declare
        l_action char(1);
    begin
        if inserting then
            l_action := 'I';
        else
            l_action := 'U';
        end if;
    
        insert into temp12_audit(id, col1, col2, col3, action, when)
        values (:new.id, :new.col1, :new.col2, :new.col3, l_action, systimestamp);
    end;
    /
    
    insert into temp12(id, col1, col2, col3) values (123, 1, 2, 3);
    insert into temp12(id, col1, col2, col3) values (456, 4, 5, 6);
    update temp12 set col1 = 9, col2 = 8 where id = 123;
    update temp12 set col1 = 7, col3 = 9 where id = 456;
    update temp12 set col3 = 7 where id = 123;
    
    select * from temp12_audit order by when;
    
            ID       COL1       COL2       COL3 A WHEN
    ---------- ---------- ---------- ---------- - -------------------------
           123          1          2          3 I 29/06/2012 15:07:47.349
           456          4          5          6 I 29/06/2012 15:07:47.357
           123          9          8          3 U 29/06/2012 15:07:47.366
           456          7          5          9 U 29/06/2012 15:07:47.369
           123          9          8          7 U 29/06/2012 15:07:47.371
    

    したがって、実行されたアクションごとに1つの監査行、2つの挿入、および3つの更新があります。ただし、変更された列ごとに個別のデータを表示する必要があります。

    select distinct id, when,
        case
            when action = 'I' then 'Record inserted'
            when prev_value is null and value is not null
                then col || ' set to ' || value
            when prev_value is not null and value is null
                then col || ' set to null'
            else col || ' changed from ' || prev_value || ' to ' || value
        end as change
    from (
        select *
        from (
            select id,
                col1, lag(col1) over (partition by id order by when) as prev_col1,
                col2, lag(col2) over (partition by id order by when) as prev_col2,
                col3, lag(col3) over (partition by id order by when) as prev_col3,
                action, when
            from temp12_audit
        )
        unpivot ((value, prev_value) for col in (
            (col1, prev_col1) as 'col1',
            (col2, prev_col2) as 'col2',
            (col3, prev_col3) as 'col3')
        )
    )
    where value != prev_value
        or (value is null and prev_value is not null)
        or (value is not null and prev_value is null)
    order by when, id;
    
            ID WHEN                      CHANGE
    ---------- ------------------------- -------------------------
           123 29/06/2012 15:07:47.349   Record inserted
           456 29/06/2012 15:07:47.357   Record inserted
           123 29/06/2012 15:07:47.366   col1 changed from 1 to 9
           123 29/06/2012 15:07:47.366   col2 changed from 2 to 8
           456 29/06/2012 15:07:47.369   col1 changed from 4 to 7
           456 29/06/2012 15:07:47.369   col3 changed from 6 to 9
           123 29/06/2012 15:07:47.371   col3 changed from 3 to 7
    

    5つの監査レコードが7つの更新になりました。 3つの更新ステートメントは、変更された5つの列を示しています。これを頻繁に使用する場合は、ビューにすることを検討してください。

    それでは、それを少しだけ分解してみましょう。コアはこの内部選択であり、 lag() そのidの以前の監査レコードから、行の以前の値を取得します :

            select id,
                col1, lag(col1) over (partition by id order by when) as prev_col1,
                col2, lag(col2) over (partition by id order by when) as prev_col2,
                col3, lag(col3) over (partition by id order by when) as prev_col3,
                action, when
            from temp12_audit
    

    これにより、すべての監査テーブル列とラグ列を含む一時ビューが得られ、 unpivot() 質問に11gのタグを付けたときに使用できる操作:

        select *
        from (
            ...
        )
        unpivot ((value, prev_value) for col in (
            (col1, prev_col1) as 'col1',
            (col2, prev_col2) as 'col2',
            (col3, prev_col3) as 'col3')
        )
    

    これで、 id、action、when、col、value、prev_valueを持つ一時的なビューができました。 列;この場合、列が3つしかないため、監査テーブルの行数は3倍になります。最後に、値が変更された行のみを含むように表示する外側の選択フィルター、つまり value!=prev_value (nullを許可します。)

    select
        ...
    from (
        ...
    )
    where value != prev_value
        or (value is null and prev_value is not null)
        or (value is not null and prev_value is null)
    

    caseを使用しています 何かを印刷するだけですが、もちろん、データを使ってやりたいことは何でもできます。 distinct insert が必要なため、 監査テーブルのエントリもピボットされていないビューで3行に変換され、最初の caseの3つすべてに同じテキストが表示されます。 条項。



    1. 手動のwhereステートメントを使用した複数の更新条件を持つCodeigniterモデル

    2. PythonでのMongoEngineによるインデックス作成の処理

    3. SELECTステートメントの列名としてクエリの結果を使用する方法

    4. M、Dはdecimal(M、D)で正確に何を意味しますか?