所以我有这张桌子:
CREATE TABLE orders_rows (
order_id NUMBER(10) PRIMARY KEY,
row_num DATE NOT NULL,
p_id NUMBER(10) NOT NULL,
quantity NUMBER(10) NOT NULL,
);
我想创建一个触发器,当更新时将数量更改为0(零) - >删除这一行。
我试过了:
CHECK_ORDER_ROW触发器:
create or replace
TRIGGER check_order_row
AFTER INSERT OR UPDATE on orders_rows
for each row
BEGIN
if :new.quantity = 0 then
DELETE_ORDER_ROW(:new.order_id, :new.row_num);
end if;
END;
DELETE_ORDER_ROW是程序:
DELETE_ORDER_ROW程序:
create or replace
PROCEDURE delete_order_row (p_order_id NUMBER, p_row_num NUMBER)
IS
BEGIN
DELETE orders_rows WHERE (order_id = p_order_id and row_num = p_row_num);
COMMIT;
END;
但是当我尝试更新时:
update orders_rows set quantity=0 where (order_id=1 and row_num=1);
我收到错误:
A trigger (or a user defined plsql function that is referenced in
this statement) attempted to look at (or modify) a table that was
in the middle of being modified by the statement which fired it.
我可以做任何改变吗?或者尝试其他选择来做到这一点?
提前致谢!
答案 0 :(得分:2)
你可能不会(或者至少你不应该)。
表上的行级触发器通常不能查询同一个表而不会导致变异表异常。如果你真的确定了,你可以创建一个包,在该包中创建一个order_id
值的集合,创建一个初始化集合的before语句触发器,创建一个用{{填充集合的行级触发器。 1}},然后是一个after语句触发器,它遍历集合并调用:new.order_id
。然而,这是很多需要处理的动作。对于将delete_order_row
设置为0以删除行的应用程序代码,通常会更有意义。将逻辑放入触发器中,删除应用程序刚插入(或更新)的行通常会导致应用程序流非常难以遵循(部分原因是您无法立即看到整个流程,因此您不断寻求查看哪些副作用触发器正在创建)以及非常难以理解和调试的错误。
如果您决定使用触发器并且不想使用三触发解决方案,则还可以重命名该表,创建名为quantity
的视图并创建{{1}触发视图,将视图上的order_row
转换为基表上的instead of
或update
,具体取决于update
值。但是,这会为您的代码添加额外的间接层,但仍然会使应用程序流难以遵循。