如何在一个 table 上编写触发器以防止更新数据但将这些数据插入另一个 table
How to write trigger on one table to prevent updating data but insert those data into other table
我想停止将数据更新到我的 bb_tax table 中并将这些数据存储到我的 tax_change_info table 中。我写了这个触发器。但如果我提出错误,则不会向我的 tax_change_info table 插入任何内容。它无一例外地工作,但它会将数据更新到我不想要的 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;
当你抛出异常然后操作失败时,你不能两者兼得。
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;
您最初的请求是捕获更改尝试并引发异常以让用户知道请求失败。接受的答案确实阻止了更新并捕获了更改尝试,但(恕我直言)这是最糟糕的失败。它不会让用户认为请求的更改没有发生;从用户的角度来看,更新是成功的。之后使用税率的任何结果都不会产生预期的结果。
现在确实不能通过触发器直接得到最初想要的结果。但是有一个解决方法。创建另一个过程以插入更改尝试。将此过程定义为 AUTONOMOUS_TRANSACTION。这允许您提交并使其与主事务分开。触发器只是调用此过程,然后在 return 上抛出异常。参见 example here。
缺点: 如果用户尝试更新多行,上面的代码只会捕获第一行,因为后续行不会被处理。要捕获所有尝试的更改,您可以使用复合触发器并在 AFTER STATEMENT 部分抛出异常。
我想停止将数据更新到我的 bb_tax table 中并将这些数据存储到我的 tax_change_info table 中。我写了这个触发器。但如果我提出错误,则不会向我的 tax_change_info table 插入任何内容。它无一例外地工作,但它会将数据更新到我不想要的 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;
当你抛出异常然后操作失败时,你不能两者兼得。
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;
您最初的请求是捕获更改尝试并引发异常以让用户知道请求失败。接受的答案确实阻止了更新并捕获了更改尝试,但(恕我直言)这是最糟糕的失败。它不会让用户认为请求的更改没有发生;从用户的角度来看,更新是成功的。之后使用税率的任何结果都不会产生预期的结果。
现在确实不能通过触发器直接得到最初想要的结果。但是有一个解决方法。创建另一个过程以插入更改尝试。将此过程定义为 AUTONOMOUS_TRANSACTION。这允许您提交并使其与主事务分开。触发器只是调用此过程,然后在 return 上抛出异常。参见 example here。
缺点: 如果用户尝试更新多行,上面的代码只会捕获第一行,因为后续行不会被处理。要捕获所有尝试的更改,您可以使用复合触发器并在 AFTER STATEMENT 部分抛出异常。