Re: History functionality
Date: Sat, 13 Mar 2004 11:06:59 +0100
Message-ID: <4052dd10$0$310$636a15ce_at_news.free.fr>
"Ed Avis" <ed_at_membled.com> a écrit dans le message de news:l1smgk4pph.fsf_at_budvar.future-i.net...
> "Michel Cadot" <micadot{at}altern{dot}org> writes:
>
> >>Now i need to have a history funtionality for a few of my
> >>tables. This must include the old values, time and date of change
> >>and user who changed the value.
>
> >Have a look at triggers:
>
> Yes, triggers are the way to do it. But it seems that wanting history
> on tables is very common and perhaps even the main use of triggers.
> Given a table definition it is possible to generate a history table
> and triggers to update the history. Is there a program to generate
> these definitions automatically?
>
> --
> Ed Avis <ed_at_membled.com>
I don't know such a program but i write the followng one in a couple of hours. I admit it is not very efficient and it does not work for long, user defined types, object types and so long. Feel free to enhance it. I don't test for 9i and timestamp column in the log table.
Def TABLE = &1
Set echo OFF
Set feedback OFF
Set heading OFF
Set linesize 2000
Set long 32760
Set newpage 0
Set pagesize 0
Set recsep OFF
Set space 0
Set trimout ON
Set trimspool ON
BTitle OFF
TTitle OFF
Set serveroutput on size 100000 format wrap
Set termout off
Col tab noprint new_value TABLE
Col log noprint new_value TABLE_LOG
Col trg noprint new_value TABLE_TRG
Col seq noprint new_value TABLE_SEQ
Col v noprint new_value version
Select upper('&TABLE') tab,
substr('&TABLE',1,26)||'_LOG' log,
substr('&TABLE',1,23)||'_LOGTRG' trg,
substr('&TABLE',1,23)||'_LOGSEQ' seq, v
from (select to_number(substr (banner, instr (banner, 'Release') + 8, 1)) v
from v$version where banner like 'Oracle%');
Set termout on
Spool GenLog_&TABLE
Declare
/* Cursor for table columns */
type col_cursor is ref cursor;
c_col col_cursor;
rcol_cur user_tab_columns.column_name%type; rcol_old user_tab_columns.column_name%type; rcol_new user_tab_columns.column_name%type; rcol_type varchar2(255);
/* 8i cursor */
c_col8 varchar2(4000) :=
'Select col.column_name col_cur,
''OLD_''||substr(col.column_name,1,26) col_new,
''NEW_''||substr(col.column_name,1,26) col_old,
col.data_type||
decode(col.data_type,
''NUMBER'', decode(col.data_precision,
NULL, decode(col.data_scale, NULL, '''', ''(38)''),
''(''||col.data_precision||
decode(col.data_scale, NULL, '')'',
'',''||col.data_scale||'')'')),
''CHAR'', ''(''||col.data_length||'')'',
''VARCHAR2'', ''(''||col.data_length||'')'',
''NCHAR'', ''(''||col.data_length||'')'',
''NVARCHAR2'', ''(''||col.data_length||'')'',
''RAW'', ''(''||col.data_length||'')''
) col_type
from user_tab_columns col
where col.table_name = :tabname
order by col.column_id';
/* 9i cursor */
c_col9 varchar2(4000) :=
'Select col.column_name col,
''OLD_''||substr(col.column_name,1,26) col_new,
''NEW_''||substr(col.column_name,1,26) col_old,
col.data_type||
''NUMBER'', decode(col.data_precision,
NULL, decode(col.data_scale, NULL, '''', ''(38)''),
''(''||col.data_precision||
decode(col.data_scale, NULL, '')'',
'',''||col.data_scale||'')'')),
''CHAR'', ''(''||col.char_length||'' ''||
decode(col.char_used,''B'',''BYTE'',''CHAR'')||'')'',
''VARCHAR2'', ''(''||col.char_length||'' ''||
decode(col.char_used,''B'',''BYTE'',''CHAR'')||'')'',
''NCHAR'', ''(''||col.char_length||'' ''||
decode(col.char_used,''B'',''BYTE'',''CHAR'')||'')'',
''NVARCHAR2'', ''(''||col.char_length||'' ''||
decode(col.char_used,''B'',''BYTE'',''CHAR'')||'')'',
''RAW'', ''(''||col.data_length||'')''
) col_type
from user_tab_columns col
where col.table_name = :tabname
order by col.column_id';
c_colt varchar2(4000);
/* Table parameters */
tabname user_tables.table_name%type;
Begin
/* Initialisations */
tabname := '&TABLE';
if &version < 9 then c_colt := c_col8; else c_colt := c_col9; end if;
dbms_output.put_line (' ');
/* Log sequence creation */
dbms_output.put_line ('create sequence &TABLE_SEQ start with 0 increment by 1');
dbms_output.put_line (' minvalue 0 nomaxvalue nocycle cache 1000 order;');
dbms_output.put_line (' ');
/* Log table creation */
dbms_output.put_line ('create table &TABLE_LOG (');
dbms_output.put_line (' id number(38),');
if &version < 9 then
dbms_output.put_line (' time date,'); else
dbms_output.put_line (' time timestamp,');
end if;
dbms_output.put_line (' username varchar2(30),');
dbms_output.put_line (' action varchar2(30),');
open c_col for c_colt using tabname;
loop
fetch c_col into rcol_cur, rcol_old, rcol_new, rcol_type;
exit when c_col%NOTFOUND;
dbms_output.put_line (' '||rcol_old||' '||rcol_type||',');
dbms_output.put_line (' '||rcol_new||' '||rcol_type||',');
end loop;
close c_col;
dbms_output.put (' constraint '||substr('&TABLE',1,23)||'_LOG_PK');
dbms_output.put_line (' primary key (id));');
dbms_output.put_line (' ');
/* Trigger creation */
dbms_output.put_line ('create or replace trigger &TABLE_TRG');
dbms_output.put_line ('after insert or update or delete on &TABLE');
dbms_output.put_line ('for each row');
dbms_output.put_line ('begin');
dbms_output.put_line (' if inserting then');
dbms_output.put_line (' insert into &TABLE_LOG (');
dbms_output.put_line (' id, time, username, action');
open c_col for c_colt using tabname;
loop
fetch c_col into rcol_cur, rcol_old, rcol_new, rcol_type;
exit when c_col%NOTFOUND;
dbms_output.put_line (' ,'||rcol_new);
end loop;
close c_col;
dbms_output.put_line (' ) values ('); if &version < 9 then
dbms_output.put_line (' &TABLE_SEQ..nextval, sysdate, user, ''INSERT'''); else
dbms_output.put_line (' &TABLE_SEQ..nextval, systimestamp, user, ''INSERT''');
end if;
open c_col for c_colt using tabname;
loop
fetch c_col into rcol_cur, rcol_old, rcol_new, rcol_type;
exit when c_col%NOTFOUND;
dbms_output.put_line (' ,:new.'||rcol_cur);
end loop;
close c_col;
dbms_output.put_line (' );');
dbms_output.put_line (' elsif deleting then');
dbms_output.put_line (' insert into &TABLE_LOG (');
dbms_output.put_line (' id, time, username, action');
open c_col for c_colt using tabname;
loop
fetch c_col into rcol_cur, rcol_old, rcol_new, rcol_type;
exit when c_col%NOTFOUND;
dbms_output.put_line (' ,'||rcol_old);
end loop;
close c_col;
dbms_output.put_line (' ) values ('); if &version < 9 then
dbms_output.put_line (' &TABLE_SEQ..nextval, sysdate, user, ''DELETE'''); else
dbms_output.put_line (' &TABLE_SEQ..nextval, systimestamp, user, ''DELETE''');
end if;
open c_col for c_colt using tabname;
loop
fetch c_col into rcol_cur, rcol_old, rcol_new, rcol_type;
exit when c_col%NOTFOUND;
dbms_output.put_line (' ,:old.'||rcol_cur);
end loop;
close c_col;
dbms_output.put_line (' );');
dbms_output.put_line (' else /* updating */');
dbms_output.put_line (' insert into &TABLE_LOG (');
dbms_output.put_line (' id, time, username, action');
open c_col for c_colt using tabname;
loop
fetch c_col into rcol_cur, rcol_old, rcol_new, rcol_type;
exit when c_col%NOTFOUND;
dbms_output.put_line (' ,'||rcol_old);
dbms_output.put_line (' ,'||rcol_new);
end loop;
close c_col;
dbms_output.put_line (' ) values ('); if &version < 9 then
dbms_output.put_line (' &TABLE_SEQ..nextval, sysdate, user, ''UPDATE'''); else
dbms_output.put_line (' &TABLE_SEQ..nextval, systimestamp, user, ''UPDATE''');
end if;
open c_col for c_colt using tabname;
loop
fetch c_col into rcol_cur, rcol_old, rcol_new, rcol_type;
exit when c_col%NOTFOUND;
dbms_output.put_line (' ,:old.'||rcol_cur);
dbms_output.put_line (' ,:new.'||rcol_cur);
end loop;
close c_col;
dbms_output.put_line (' );');
dbms_output.put_line (' end if;');
dbms_output.put_line ('end;');
dbms_output.put_line ('/');
dbms_output.put_line (' ');
End;
/
Spool off
Regards
Michel Cadot
Received on Sat Mar 13 2004 - 11:06:59 CET
