Как написать триггер в одной таблице, чтобы предотвратить обновление данных, но вставить эти данные в другую таблицу

avatar
Vahida Vadiya
8 августа 2021 в 18:06
51
2
1

Я хочу остановить обновление данных в моей таблице bb_tax и сохранить эти данные в моей таблице tax_change_info. Я написал этот триггер. но ничего не вставляется в мою таблицу tax_change_info, если я вызываю ошибку. он работает без исключения, но он будет обновлять данные в моем bb_tax, чего я не хочу. Как мне написать триггер для этого?

вот мой триггер.

CREATE OR REPLACE TRIGGER CHECK_TAX_RATE
BEFORE UPDATE OF taxrate 
ON BB_TAX 
FOR EACH ROW  
DECLARE 
v_user varchar(50);

BEGIN 
    select user into v_user from dual;
    INSERT INTO TAX_CHANGE_INFO VALUES(v_user,:OLD.TAXRATE, :NEW.TAXRATE);
    dbms_output.put_line('insert done');
    
    RAISE_APPLICATION_ERROR(-20505,'You are not allowed to update taxes.');   
END;
Источник

Ответы (2)

avatar
Belayer
9 августа 2021 в 21:45
1

Ваш первоначальный запрос состоял в том, чтобы зафиксировать попытку изменения и создать исключение, чтобы сообщить пользователю, что запрос не выполнен. Принятый ответ предотвращает обновление и фиксирует попытку изменения, но (имхо) это худший сбой. Не дает пользователю понять, что запрошенное изменение не произошло; с точки зрения пользователя обновление прошло успешно. Любой результат использования налоговой ставки впоследствии не дает ожидаемого результата.
Сейчас правда нельзя получить начальные желаемые результаты напрямую через триггер. Но есть обходной путь. Создайте еще одну процедуру для вставки попытки изменения. Определите эту процедуру как AUTONOMOUS_TRANSACTION. Это позволяет вам зафиксировать и при этом сохранить его отдельно от основной транзакции. Триггер просто вызывает эту процедуру, а по возвращении выдает исключение. См. пример здесь.

Недостаток: Если пользователь попытается обновить несколько строк, описанное выше захватит только 1-ю, поскольку последующие строки не обрабатываются. Чтобы зафиксировать все попытки изменений, вы можете использовать составной триггер и создать исключение в разделе AFTER STATEMENT.

Vahida Vadiya
12 августа 2021 в 04:25
0

Да, ты прав. Я так же думал, что это не позволит пользователям узнать, что данные на самом деле не были обновлены.

avatar
Wernfried Domscheit
8 августа 2021 в 18:43
4

Когда вы вызываете исключение, операция завершается сбоем, вы не можете иметь и то, и другое. Триггер BEFORE UPDATE не имеет значения :NEW.

Если вы хотите предотвратить обновление, вы можете сделать это следующим образом:

CREATE OR REPLACE TRIGGER CHECK_TAX_RATE
   AFTER UPDATE OF taxrate ON BB_TAX 
   FOR EACH ROW      
BEGIN 
    -- no need for 'select user into v_user from dual;'
    INSERT INTO TAX_CHANGE_INFO VALUES(USER, :OLD.TAXRATE, :NEW.TAXRATE);
    :NEW.TAXRATE := :OLD.TAXRATE;
END;
Vahida Vadiya
9 августа 2021 в 20:28
0

Спасибо за ответ. Я попробовал, но выдает ошибку для инструкции :NEW.TAXRATE := :OLD.TAXRATE; «ORA-04084: невозможно изменить НОВЫЕ значения для этого типа триггера»

Vahida Vadiya
9 августа 2021 в 20:35
0

Я использовал перед триггером и отдыхом так же, как у вас, и это сработало как шарм. Большое спасибо