2013-10-03 20 views
10

Ho bisogno di ottenere tutti i valori che sono cambiati in una riga e postare modifiche su un'altra tabella di 'controllo'. Posso realizzare questo, senza scrivere le condizioni per ogni elemento dalla riga? So che lo SQL da http://www.firebirdfaq.org/faq133/ che ti dà tutte le condizioni per verifiche:Firebird: ottiene tutti i campi modificati all'interno di un trigger

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'; 

ma questo dovrebbe essere scritto nel trigger. Quindi, se cambio un tavolo, devo modificare il trigger.

A causa del fatto che FireBird non consente di aumentare dinamicamente la dimensione di una variabile varchar, pensavo di trasmettere e concatenare tutti i valori a una grande variabile varchar, prima di inserirlo in un blob di testo.

Esiste la possibilità di eseguire questa operazione, senza utilizzare GTTs?

risposta

4

È necessaria qualche meta programmazione, ma con i trigger sulle tabelle di sistema non c'è problema.

Questa soluzione sembra funzionare, anche se ci sono molte colonne.

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 per inventiva ... ma funziona? [Questo thread di mailing list] (http://groups.yahoo.com/neo/groups/firebird-support/conversations/topics/100294) suggerisce che ① i trigger di tabella di sistema svaniscono quando alcuni tavoli vengono DROPped, e ② questo approccio a meno usato per essere in crash. – pilcrow

4

Questo strumento è la soluzione Firebirds per il vostro problema:

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

In caso contrario non è possibile accedere al new./old. variabili dinamicamente.

Ho studiato una soluzione basata su istruzioni di esecuzione, ma è anche un vicolo cieco.

Utilizzando EXECUTE STATEMENT con una variabile di contesto (nuovo o vecchio) sarà mai funzionato, causa che è disponibile solo all'interno di un trigger, non in una nuova dichiarazione (l'istruzione EXECUTE) non viene eseguita all'interno del grilletto, sebbene usi la stessa connessione e transazione.

+0

Non riesco a utilizzare un altro strumento. Deve essere fatto "in casa". Grazie. – RBA

+1

In questo caso, penso che il modo migliore per creare alcune stored procedure per rigenerare i trigger e programmarli per l'esecuzione giornaliera (o quando si eseguono DDL-s nel database). –

Problemi correlati