Oracle - Triggers to create a history row on update

后端 未结 7 547
天命终不由人
天命终不由人 2021-02-04 16:28

First, we currently have the behavior that\'s desired, but it\'s not trivial to maintain when any changes to the database are needed. I\'m looking for anything simpler, more ef

7条回答
  •  小鲜肉
    小鲜肉 (楼主)
    2021-02-04 16:46

    I understand your specifc application requirements to have the history and current values in the same table, but perhaps this could be handled by going down the more usual route of having a separate audit table but building it up as a pseudo-materialized view to present a combined view for the application.

    For me, this has the advantage of having a simple "current" view and a separate but completely automated "audit" view (which in this case also has the current view).

    Something like:

    create sequence seq_contact start with 1000 increment by 1 nocache nocycle;
    
    create table contact (
        contact_id integer,
        first_name varchar2(120 char),
        last_name varchar2(120 char),
        last_update_date date
        );
    
    alter table contact add constraint pk_contact primary key (contact_id);
    
    create table a$contact (
        version_id integer,
        contact_id integer,
        first_name varchar2(120 char),
        last_name varchar2(120 char),
        last_update_date date
        );
    
    alter table a$contact add constraint pk_a$contact primary key
            (contact_id, version_id);
    
    create or replace trigger trg_contact
    before insert or delete or update on contact 
    for each row
    declare
    
        v_row contact%rowtype;
        v_audit a$contact%rowtype;
    
    begin
    
        select seq_contact.nextval into v_audit.version_id from dual;
    
        if not deleting then
    
            :new.last_update_date := sysdate;
    
        end if;
    
        if inserting or updating then
    
            v_audit.contact_id := :new.contact_id;
            v_audit.first_name := :new.first_name;
            v_audit.last_name := :new.last_name;
            v_audit.last_update_date := :new.last_update_date;
    
        elsif deleting then
    
            v_audit.contact_id := :old.contact_id;
            v_audit.first_name := :old.first_name;
            v_audit.last_name := :old.last_name;
            v_audit.last_update_date := sysdate;
    
        end if;
    
        insert into a$contact values v_audit;
    
    end trg_contact;
    /
    
    insert into contact (contact_id, first_name, last_name) values
        (1,'Nick','Pierpoint');
    
    insert into contact (contact_id, first_name, last_name) values
        (2, 'John', 'Coltrane');
    
    insert into contact (contact_id, first_name, last_name) values
        (3, 'Sonny', 'Rollins');
    
    insert into contact (contact_id, first_name, last_name) values
        (4, 'Kenny', 'Wheeler');
    
    update contact set last_name = 'Cage' where contact_id = 1;
    
    delete from contact where contact_id = 1;
    
    update contact set first_name = 'Zowie' where contact_id in  (2,3);
    
    select * from a$contact order by contact_id, version_id;
    
    VERSION_ID  CONTACT_ID  FIRST_NAME  LAST_NAME  LAST_UPDATE_DATE
    1000        1           Nick        Pierpoint  11/02/2010 14:53:49
    1004        1           Nick        Cage       11/02/2010 14:54:00
    1005        1           Nick        Cage       11/02/2010 14:54:06
    1001        2           John        Coltrane   11/02/2010 14:53:50
    1006        2           Zowie       Coltrane   11/02/2010 14:54:42
    1002        3           Sonny       Rollins    11/02/2010 14:53:51
    1007        3           Zowie       Rollins    11/02/2010 14:54:42
    1003        4           Kenny       Wheeler    11/02/2010 14:53:53
    

提交回复
热议问题