2016-08-16 1 views
1

Я хотел бы написать триггер, который проверяет перед вставкой на таблицу, чтобы увидеть, есть ли в этой таблице существующие записи с теми же fk_id и active flag. Например представьте следующую таблицу:Оракул - исключение из таблицы Mutating Table в триггере?

| row_id | fk_id | active_flag | 
| ------------------------------| 
| 1 | 500 |   1 | 
| 2 | 500 |   0 | 
| 3 | 501 |   1 | 

сказать, что я хочу, чтобы вставить новую строку с fk_id = 500 и active_flag = 1. Я хочу сделать исключение, потому что, основываясь на моих правилах, вы не можете иметь две строки с одинаковыми fk_id, которые также являются активными в этой таблице в любой момент времени.

я написал триггер, чтобы попытаться справиться с этим:

CREATE OR REPLACE TRIGGER MYSCHEMA.CHECK_DUPS_BIU 

BEFORE INSERT OR UPDATE ON MYSCHEMA.MYTABLE_T FOR EACH ROW 
DECLARE 
    l_cnt NUMBER; 
    e_dup EXCEPTION; 
BEGIN 

    SELECT COUNT(*) 
    INTO l_cnt 
    FROM MYSCHEMA.MYTABLE_T 
    WHERE fk_id = :new.fk_id 
    AND active_flag > 0; 

    IF(l_cnt > 0) 
    THEN 
     RAISE e_dup; 
    END IF; 

EXCEPTION 
WHEN e_dup THEN 
    raise_application_error(-20300, 'You cannot insert two active items with the same fk_id'); 
END CHECK_DUPS_BIU; 
/

С этим триггером работает совершенно нормально на вставках, но когда я делаю обновление, я получаю исключение Mutating таблицы:

ORA-04091: table MYSCHEMA.CHECK_DUPS_BIU is mutating, trigger/function may not see it 
ORA-06512: at "MYSCHEMA.CHECK_DUPS_BIU ", line 12 
ORA-04088: error during execution of trigger 'MYSCHEMA.CHECK_DUPS_BIU ' 

Я сделал небольшое исследование по этой проблеме, и я прочитал, что лучший способ справиться с такой ситуацией * может заключаться в использовании ограничения, но я не уверен, как закодировать такое ограничение, которое проверяет другой столбец (active_flag).

Как я могу осуществить такую ​​проверку?

+0

Вы уверены, что видите скомпилированный код? Ошибка Mutating возникает, когда вы выполняете какую-либо операцию в той же таблице, для которой вы создаете 'before trigger' for. Поэтому, скорее всего, код, который вы показываете, не является фактическим кодом, который вы видите. –

+0

Да, я только что обновил логику, которую я показывал в своем первоначальном вопросе. Вы правы, раньше это было неправильно. –

+0

Ну, так как вы отредактировали свой код, изменив таблицу, которую вы делаете, выберите проблему, как я уже сказал в предыдущем комментарии. Вы не можете выполнить какую-либо операцию выбора в той же таблице, в которой вы создали свой 'before trigger' –

ответ

6

Не использовать триггер, используйте уникальную функцию на основе индекса:

create unique index myindex on mytable (case when active_flag=1 then fk_id end); 

Когда active_flag не 1, запись не будет храниться в индексе; когда active_flag равно 1, запись будет сохранена - но исключение будет поднято, если тот же fk_id уже существует.

+0

Это, кажется, отлично работает. Я не очень разбираюсь в ограничениях, поэтому это было большой помощью. Спасибо! –

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