Как хранить данные истории изменений в Oracle и обрабатывать неизмененные значения - PullRequest
0 голосов
/ 19 июня 2019

Эй, ребята, у меня есть одна таблица с именем Users: enter image description here

Затем у меня есть другая таблица с изменениями, внесенными в таблицу выше, которая называется Users_History_Changes: enter image description here

Я знаю, что мне нужен триггер, который срабатывает, когда одна таблица обновляется и вставляет значения в таблицу Users_History_Changes.Но вот что я не могу сделать.Когда журнал создается в таблице Users_History_Changes и обновляется только Last_Name, остальные поля должны оставаться пустыми.Затем имя First_Name изменяется, поэтому таблица показывает только это.В конце мы меняем возраст, и пользователь с ID = 1 становится с 'Raul Peres, 25' на 'Pedro Felipes, 30'.Time_Stamp - это когда изменение сделано.

Ответы [ 2 ]

2 голосов
/ 19 июня 2019

Вы можете проверить, изменилось ли каждое значение как часть вставки в таблицу истории:

create trigger users_trigger
before insert or update on users
for each row
begin
  insert into users_history_changes (id, first_name, last_name, age, timestamp_changes)
  values (:new.id,
    case when :old.first_name is null or :new.first_name != :old.first_name then :new.first_name end,
    case when :old.last_name is null or :new.last_name != :old.last_name then :new.last_name end,
    case when :old.age is null or :new.age != :old.age then :new.age end,
    systimestamp);
end;
/

Вероятно, бесполезно проверять, изменилось ли значение на null, так как это не будет очень полезной историей, поэтому я проверил только из null.И даже эти тесты могут / должны быть расширены для охвата крайних случаев, например, для проверки того, что что-то действительно изменилось.

В любом случае, со следующими утверждениями:

insert into users
select 1, 'Raul', 'Peres', 25 from dual
union all select 2, 'Francis', 'Lotters', 40 from dual
union all select 3, 'Maria', 'Lopez', 39 from dual;

update users set last_name = 'Felipes' where id = 1;
update users set first_name = 'Pedro' where id = 1;
update users set age = 30 where id = 1;

update users set first_name = 'Maria', last_name = 'Sanchez', age = 40 where id = 3;

таблица истории заканчивается:

        ID FIRST_NAME LAST_NAME         AGE TIMESTAMP_CHANGES           
---------- ---------- ---------- ---------- ----------------------------
         1 Raul       Peres              25 19-JUN-19 20.02.33.470409000
         2 Francis    Lotters            40 19-JUN-19 20.02.33.473139000
         3 Maria      Lopez              39 19-JUN-19 20.02.33.473183000
         1            Felipes               19-JUN-19 20.02.33.548101000
         1 Pedro                            19-JUN-19 20.02.33.594305000
         1                               30 19-JUN-19 20.02.33.640293000
         3            Sanchez            40 19-JUN-19 20.02.33.688710000

db <> fiddle

В качестве альтернативы, если вы хотите, чтобы одна строка на каждое измененное значение, вы могли бы использовать updating предложение:

create trigger users_trigger
before insert or update on users
for each row
begin
  if inserting then
    insert into users_history_changes (id, first_name, last_name, age, timestamp_changes)
    values (:new.id, :new.first_name, :new.last_name, :new.age, systimestamp);
  end if;

  if updating ('FIRST_NAME') then
    insert into users_history_changes (id, first_name, timestamp_changes)
    values (:new.id, :new.first_name, systimestamp);
  end if;
  if updating ('LAST_NAME') then
    insert into users_history_changes (id, last_name, timestamp_changes)
    values (:new.id, :new.last_name, systimestamp);
  end if;
  if updating ('AGE') then
    insert into users_history_changes (id, age, timestamp_changes)
    values (:new.id, :new.age, systimestamp);
  end if;
end;
/

, но при этом будет создана строка для значений, которые «изменены» на то же значение, если только вы не добавите дополнительную логику для проверки фактических изменений - проверка updating() заключается в том, что обновлениеоператор включил столбец в свой список set. дб <> скрипка

0 голосов
/ 19 июня 2019

Вы можете сравнить новые и старые значения для регистрации обновлений

create or replace trigger trg_users on users
after insert or update 
for each row
declare
  v_dml_type varchar2(1);

  procedure pr_upd_log( i_dml_type varchar2, i_col_name varchar2, 
                        i_old_val  varchar2, i_new_val  varchar2 ) is
  begin
    insert into Users_History_Changes( dml_type, col_name, old_val, new_val )
     values( i_dml_type, i_col_name, i_old_val, i_new_val );
  end;
begin

  if updating then v_dml_type := 'U';
  elsif inserting then v_dml_type := 'I'; end if; 

  if ( nvl(:old.user_id,-987) != nvl(:new.user_id,-987) ) then     
     pr_upd_log(v_dml_type,'user_id',to_char(:old.user_id),to_char(:new.user_id));
  end if;

  if ( nvl(:old.age,-987) != nvl(:new.age,-987) ) then     
     pr_upd_log(v_dml_type,'age',to_char(:old.age),to_char(:new.age));
  end if;

  if ( nvl(:old.first_name,'NuLLxYZ') != nvl(:new.first_name,'NuLLxYZ') ) then     
     pr_upd_log(v_dml_type,'first_name',:old.first_name,:new.first_name);
  end if;

  if ( nvl(:old.last_name,'NuLLxYZ') != nvl(:new.last_name,'NuLLxYZ') ) then     
     pr_upd_log(v_dml_type,'last_name',:old.last_name,:new.last_name);
  end if;     
  -- for v_dml_type = 'I', use your former way
end;
...