2017-02-21 10 views
0

У меня есть следующие данные в таблицеРекурсивный триггер обработки

DEPT  ID  ICCODE  OTHER FIELDS 
    ====  ===  =====  ============ 
    10   2  FA   Data1 
    20   2  FA   Data2 
    30   2  FA   Data3 

Каждый отдел принадлежит некоторому внешнему приложению. Если какое-либо внешнее приложение изменяет ICCODE для любого отдела, я должен обновить два других отдела ICCODE с тем же значением.

Я пишу триггер на столбце ICCODE и обновляя две другие записи, но здесь проблема заключается в том, что триггер находится в том же столбце, а в триггере снова изменяются те же значения столбцов для разных строк. Это вызывает тупиковую ситуацию. Может ли кто-нибудь, пожалуйста, сообщить мне решение об этом или обходных решениях? Я не могу изменить структуру приведенной выше таблицы, но при необходимости могу создать новые. Проблема здесь внешние приложения только обновляет эту таблицу ...

С уважением

+0

Как выглядит ваш текущий триггер? Вы на самом деле получаете тупик или ошибку с изменением таблицы, которая сильно отличается? –

+0

Получение тупика. Первоначально полученная ошибка мутационной таблицы, а затем я использовал pragma autonomous_transaction; исправить и получить тупиковую ошибку. – Bujji

ответ

1

Ваша модель данных является проблемой, потому что она должна быть нормализована, как предложил Рене. Однако, учитывая, что вы не можете этого сделать, и поскольку часть вашей проблемы уже была ошибкой с ошибкой (из комментария); и Предполагая, что вы на высоте 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, несмотря на то, что, по-видимому, обновляется только одна строка.

Фиксация модели данных по-прежнему будет намного лучше, но такой подход может сделать как обходное решение с учетом ваших ограничений.

+0

Большое спасибо за это решение. Я не знал о сложных триггерах. Перед тем, как получить решение, я сделал: 1) Создал триггер в таблице и вставил данные во временную таблицу 2) Создал планировщик, который слушает каждую секунду в этой временной таблице и видит, есть ли новые записи. 3) Если есть новые записывает его, обновляет основную таблицу со значениями (даже в этом случае он снова запускает триггер, но у меня есть условие, которое помещается в запрос, чтобы проверить фиктивную таблицу, чтобы увидеть, была ли она уже обработана записью или нет. Если это не так, обрабатывается в противном случае, он игнорируется. – Bujji

+0

Это действительно замечательное решение :) – Bujji

0

Вы должны создать таблицу со столбцом ID и столбца CODE и хранить ICCODE в этой таблице

ID ICCODE 
== ==== 
1 FA 

Измените таблицу так, чтобы она содержала идентификатор таблицы ICCODE вместо самого кода.

DEPT  ID  IC_ID  OTHER FIELDS 
    ====  ===  =====  ============ 
    10   2  1   Data1 
    20   2  1   Data2 
    30   2  1   Data3 

При необходимости обновите код в таблице ICCODE.

Поиск ICCODE при запросе таблицы.

+0

Прошу прощения, у меня нет контроля над существующей таблицей. Я могу создавать новые таблицы, но не могу внести изменения в существующую таблицу. – Bujji

Смежные вопросы