2013-10-03 2 views
10

행에 변경된 값을 가져와 다른 '감사'테이블에 수정 사항을 게시해야합니다. 행에서 각 요소에 대한 조건을 작성하지 않고도이 작업을 수행 할 수 있습니까? 나는 당신에게 검증을위한 모든 조건을 제공 http://www.firebirdfaq.org/faq133/에서 SQL 알고Firebird - 트리거 내에서 수정 된 모든 필드 가져 오기

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 변수로 캐스팅하고 연결하려고 생각했습니다.

GTTs을 사용하지 않고이 작업을 수행 할 수 있습니까?

http://www.upscene.com/products.audit.iblm_main.php

그렇지 않으면 당신은 new./old에 액세스 할 수 없습니다 :

답변

4

일부 메타 프로그래밍이 필요하지만 시스템 테이블의 트리거는 문제가되지 않습니다.

이 솔루션은 많은 열이 있어도 작동하는 것으로 보입니다.

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 ;^
+4

창의력 +1 ...하지만 작동합니까? [이 메일 링리스트 스레드] (http://groups.yahoo.com/neo/groups/firebird-support/conversations/topics/100294)는 어떤 테이블이 DROPped 될 때 시스템 테이블 트리거가 사라지고, 적어도 충돌하는 데 사용되었습니다. – pilcrow

4

이 도구는 문제에 대한 firebirds 솔루션입니다. 변수를 동적으로.

실행 문을 기반으로 한 솔루션을 조사했지만 막 다른 골목이기도합니다. , 컨텍스트 변수 (NEW 또는 OLD) 것이다 가 작동하지 않습니다와 함께 문을 실행 즉 (EXECUTE 문) 트리거 내에서 실행되지 않습니다으로 새 성명에서, 트리거 내부에서만 사용할 수 원인이 사용

, 동일한 연결과 트랜잭션을 사용합니다.

+0

다른 도구를 사용할 수 없습니다. '사내에서'만들어야합니다. 고맙습니다. – RBA

+1

이 경우 트리거를 재생성하기 위해 몇 가지 저장 프로 시저를 작성하고 매일 실행하도록 (또는 데이터베이스에서 DDL-s를 실행할 때) 예약하는 것이 가장 좋은 방법이라고 생각합니다. –