procedure-trigger
Есть процедура генерации универсальных триггеров, которые логируют изменения в любой таблице, для всех столбцов, но развёрнуто по вертикали в универсальные таблицы логов
Пример процедуры:
create or replace procedure p$chglog_make_trigger (p_table varchar2)authid current_user as
--
procedure s(p_text varchar2)is
begin
DBMS_OUTPUT.PUT_LINE(p_text);
end;
--
procedure ins_cols(p_alias varchar2)is
v_new char(1):=case when LOWER(p_alias)='new' then '1' else '0' end;
v_col varchar2(40);
begin
for c in (select column_name n,data_type t from user_tab_columns
where table_name=upper(p_table)) loop
v_col:=':'||p_alias||'.'||c.n;
if c.t='NUMBER' then
S(' insert into x$chglog_value(id,col,new,chr,num)values(v_id,'''||c.n||''''||
','''||v_new||''',to_char('||v_col||'),'||v_col||');');
elsif c.t='DATE' then
S(' insert into x$chglog_value(id,col,new,chr,dat)values(v_id,'''||c.n||''''||
','''||v_new||''',to_char('||v_col||',''DD.MM.YYYY''||');
S(' case when '||v_col||'<>trunc('||v_col||') then '' HH24:MI:SS'' end),'||v_col||');');
elsif c.t in('CHAR','VARCHAR2') then
S(' insert into x$chglog_value(id,col,new,chr)values(v_id,'''||c.n||''''||
','''||v_new||''','||v_col||');');
end if;
end loop;
end;
--
begin
S('create or replace trigger '||p_table||'_cl');
S('before insert or update or delete on '||p_table);
S('for each row');
S('declare');
S(' v_cmd char(1):=case when inserting then ''I'' when updating then ''U'' else ''D'' end;');
S(' v_id int;');
S('begin');
S(' insert into x$chglog(tbl,cmd)values('''||p_table||''',v_cmd)');
S(' returning id into v_id;');
S(' if updating or deleting then');
ins_cols('old');
S(' end if;');
S(' if inserting or updating then');
ins_cols('new');
S(' end if;');
S('end;');
S('/');
end;
/
и триггер:
CREATE OR REPLACE TRIGGER "TMS_SYSS_CL"
BEFORE INSERT OR UPDATE OR DELETE ON TMS_SYSS
FOR EACH ROW
DECLARE
v_cmd CHAR(1):=CASE WHEN INSERTING THEN 'I' WHEN UPDATING THEN 'U' ELSE 'D' END;
v_id INT;
BEGIN
INSERT INTO X$CHGLOG(tbl,cmd)VALUES('TMS_SYSS',v_cmd)
RETURNING ID INTO v_id;
IF UPDATING OR DELETING THEN
INSERT INTO X$CHGLOG_VALUE(ID,COL,NEW,CHR,num)VALUES(v_id,'COD1','0',TO_CHAR(:OLD.COD1),:OLD.COD1);
INSERT INTO X$CHGLOG_VALUE(ID,COL,NEW,CHR)VALUES(v_id,'DENUMIREA','0',:OLD.DENUMIREA);
INSERT INTO X$CHGLOG_VALUE(ID,COL,NEW,CHR)VALUES(v_id,'UM','0',:OLD.UM);
INSERT INTO X$CHGLOG_VALUE(ID,COL,NEW,CHR,num)VALUES(v_id,'NUMBER1','0',TO_CHAR(:OLD.NUMBER1),:OLD.NUMBER1);
INSERT INTO X$CHGLOG_VALUE(ID,COL,NEW,CHR,num)VALUES(v_id,'NUMBER2','0',TO_CHAR(:OLD.NUMBER2),:OLD.NUMBER2);
INSERT INTO X$CHGLOG_VALUE(ID,COL,NEW,CHR,num)VALUES(v_id,'PRET','0',TO_CHAR(:OLD.PRET),:OLD.PRET);
INSERT INTO X$CHGLOG_VALUE(ID,COL,NEW,CHR)VALUES(v_id,'TIP','0',:OLD.TIP);
INSERT INTO X$CHGLOG_VALUE(ID,COL,NEW,CHR,num)VALUES(v_id,'COD','0',TO_CHAR(:OLD.COD),:OLD.COD);
END IF;
IF INSERTING OR UPDATING THEN
INSERT INTO X$CHGLOG_VALUE(ID,COL,NEW,CHR,num)VALUES(v_id,'COD1','1',TO_CHAR(:NEW.COD1),:NEW.COD1);
INSERT INTO X$CHGLOG_VALUE(ID,COL,NEW,CHR)VALUES(v_id,'DENUMIREA','1',:NEW.DENUMIREA);
INSERT INTO X$CHGLOG_VALUE(ID,COL,NEW,CHR)VALUES(v_id,'UM','1',:NEW.UM);
INSERT INTO X$CHGLOG_VALUE(ID,COL,NEW,CHR,num)VALUES(v_id,'NUMBER1','1',TO_CHAR(:NEW.NUMBER1),:NEW.NUMBER1);
INSERT INTO X$CHGLOG_VALUE(ID,COL,NEW,CHR,num)VALUES(v_id,'NUMBER2','1',TO_CHAR(:NEW.NUMBER2),:NEW.NUMBER2);
INSERT INTO X$CHGLOG_VALUE(ID,COL,NEW,CHR,num)VALUES(v_id,'PRET','1',TO_CHAR(:NEW.PRET),:NEW.PRET);
INSERT INTO X$CHGLOG_VALUE(ID,COL,NEW,CHR)VALUES(v_id,'TIP','1',:NEW.TIP);
INSERT INTO X$CHGLOG_VALUE(ID,COL,NEW,CHR,num)VALUES(v_id,'COD','1',TO_CHAR(:NEW.COD),:NEW.COD);
END IF;
END;
/