11

行で変更されたすべての値を取得し、他の「監査」テーブルに変更を投稿する必要があります。行から各要素の条件を記述せずに、これを達成できますか? http://www.firebirdfaq.org/faq133/の SQL を知っています。これにより、検証のすべての条件が得られます。

select 'if (new.' || rdb$field_name || ' is null and old.' ||
rdb$field_name || ' is not null or new.' || rdb$field_name ||
'is not null and old.' || rdb$field_name || ' is null or new.' ||
rdb$field_name || ' <> old.' || rdb$field_name || ') then'
from rdb$relation_fields
where rdb$relation_name = 'EMPLOYEE';

ただし、これはトリガーに書き込む必要があります。したがって、テーブルを変更する場合は、トリガーを変更する必要があります。

FireBird では varchar 変数のサイズを動的に増やすことができないため、テキスト BLOB に挿入する前に、すべての値を大きな varchar 変数にキャストして連結することを考えていました。

GTTを使用せずにこれを達成する可能性はありますか?

4

2 に答える 2

5

ある程度のメタ プログラミングが必要ですが、システム テーブルにトリガーがあれば問題ありません。

列がたくさんある場合でも、このソリューションは機能するようです。

set term ^ ;

create or alter procedure create_audit_update_trigger (tablename char(31)) as
    declare sql blob sub_type 1;
    declare fn char(31);
    declare skip decimal(1);
begin
    -- TODO add/remove fields to/from audit table

    sql = 'create or alter trigger ' || trim(tablename) || '_audit_upd for ' || trim(tablename) || ' after update as begin if (';

    skip = 1;
    for select rdb$field_name from rdb$relation_fields where rdb$relation_name = :tablename into :fn do
    begin
        if (skip = 0) then sql = sql || ' or ';
        sql = sql || '(old.' || trim(:fn) || ' is distinct from new.' || trim(:fn) || ')';
        skip = 0;
    end
    sql = sql || ') then insert into ' || trim(tablename) || '_audit (';

    skip = 1;
    for select rdb$field_name from rdb$relation_fields where rdb$relation_name = :tablename into :fn do
    begin
        if (skip = 0) then sql = sql || ',';
        sql = sql || trim(:fn);
        skip = 0;
    end
    sql = sql || ') values (';

    skip = 1;
    for select rdb$field_name from rdb$relation_fields where rdb$relation_name = :tablename into :fn do
    begin
        if (skip = 0) then sql = sql || ',';
        sql = sql || 'new.' || trim(:fn);
        skip = 0;
    end
    sql = sql || '); end';

    execute statement :sql;
end ^

create or alter trigger field_audit for rdb$relation_fields after insert or update or delete as
begin
    -- TODO filter table name, don't include system or audit tables
    -- TODO add insert trigger
    execute procedure create_audit_update_trigger(new.rdb$relation_name);
end ^

set term ; ^
于 2013-10-14T14:14:20.400 に答える