Ваша модель данных является проблемой, потому что она должна быть нормализована, как предложил Рене. Однако, учитывая, что вы не можете этого сделать, и поскольку часть вашей проблемы уже была ошибкой с ошибкой (из комментария); и Предполагая, что вы на высоте 11 г или выше, вы можете решить обе проблемы с помощью сложного триггера.
Это один из способов избежать ошибки мутирующей таблицы, поскольку он позволяет вам поддерживать список затронутых строк, которые строятся на уровне строк, а затем использовать эту коллекцию позже на уровне инструкций.
Эта идея просто изменяет, что немного также отслеживать ли вы ударяете на спусковой крючок во второй раз в вашем триггере уровне заявление, которое можно использовать, чтобы избежать рекурсии:
Давайте начнем с фиктивной таблицы и данные первый:
create table t42 (DEPT number, ID number, ICCODE varchar2(2), OTHER_FIELDS varchar2(10));
insert into t42 (dept, id, iccode, other_fields) values (10, 1, 'FA', 'Data1');
insert into t42 (dept, id, iccode, other_fields) values (20, 2, 'FA', 'Data2');
insert into t42 (dept, id, iccode, other_fields) values (30, 3, 'FA', 'Data3');
insert into t42 (dept, id, iccode, other_fields) values (40, 4, 'XY', 'Data4');
Без триггера, обновление одной строки, как:
update t42 set iccode = 'AF' where id = 1;
будет только установить, что значение Однорядового к AF. С помощью составного триггера, который управляет коллекцией, которую вы можете обновить после триггера после оператора, но это будет вызываться рекурсивно.
Так что это использует dbms_application_info
(или какой-либо другой механизм), чтобы увидеть пришло ли обновление от триггера себя, или где-нибудь еще:
create or replace trigger test_trigger
for update of iccode on t42
compound trigger
-- collection to hold old and new values
type t_changed_row is record (old_value t42.iccode%type, new_value t42.iccode%type);
type t_changed_rows is table of t_changed_row;
l_changed_rows t_changed_rows := t_changed_rows();
l_fixed_info constant varchar2(30) := 'compound trigger hack';
after each row is
l_info varchar2(30);
begin
dbms_application_info.read_client_info(l_info);
if l_info is null or l_info != l_fixed_info then
-- not in nested update; store old and new values
l_changed_rows.extend;
l_changed_rows(l_changed_rows.count).old_value := :old.iccode;
l_changed_rows(l_changed_rows.count).new_value := :new.iccode;
end if;
end after each row;
after statement is
l_old_info varchar2(30);
begin
-- could check current value here as well but may not be worth it;
-- the collection will be empty anyway on second-level hit
-- store existing value to restore later
dbms_application_info.read_client_info(l_old_info);
-- set info to block recursion
dbms_application_info.set_client_info(l_fixed_info);
-- update table based on all old/new value pairs at once
forall i in 1..l_changed_rows.count
update t42
set iccode = l_changed_rows(i).new_value
where iccode = l_changed_rows(i).old_value;
-- reset info
dbms_application_info.set_client_info(l_old_info);
end after statement;
end test_trigger;
/
И это сейчас обновляет все значения соответствия:
update t42 set iccode = 'AF' where id = 1;
1 row updated.
select * from t42;
DEPT ID IC OTHER_FIEL
---------- ---------- -- ----------
10 1 AF Data1
20 2 AF Data2
30 3 AF Data3
40 4 XY Data4
Все значения FA были изменены на AF, несмотря на то, что, по-видимому, обновляется только одна строка.
Фиксация модели данных по-прежнему будет намного лучше, но такой подход может сделать как обходное решение с учетом ваших ограничений.
Как выглядит ваш текущий триггер? Вы на самом деле получаете тупик или ошибку с изменением таблицы, которая сильно отличается? –
Получение тупика. Первоначально полученная ошибка мутационной таблицы, а затем я использовал pragma autonomous_transaction; исправить и получить тупиковую ошибку. – Bujji