我需要获取所有连续更改的值,并在其他“审核”表上发布修改内容。我可以在不编写行中每个元素的条件的情况下完成此操作吗?我知道来自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,是否有可能做到这一点?
您需要一些元编程,但是在系统表上使用触发器是没有问题的。
即使您有很多列,此解决方案似乎仍然有效。
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 ; ^