创建删除行的触发器

时间:2015-03-31 18:21:04

标签: oracle plsql triggers procedure

所以我有这张桌子:

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.

我可以做任何改变吗?或者尝试其他选择来做到这一点?

提前致谢!

1 个答案:

答案 0 :(得分:2)

你可能不会(或者至少你不应该)。

表上的行级触发器通常不能查询同一个表而不会导致变异表异常。如果你真的确定了,你可以创建一个包,在该包中创建一个order_id值的集合,创建一个初始化集合的before语句触发器,创建一个用{{填充集合的行级触发器。 1}},然后是一个after语句触发器,它遍历集合并调用:new.order_id。然而,这是很多需要处理的动作。对于将delete_order_row设置为0以删除行的应用程序代码,通常会更有意义。将逻辑放入触发器中,删除应用程序刚插入(或更新)的行通常会导致应用程序流非常难以遵循(部分原因是您无法立即看到整个流程,因此您不断寻求查看哪些副作用触发器正在创建)以及非常难以理解和调试的错误。

如果您决定使用触发器并且不想使用三触发解决方案,则还可以重命名该表,创建名为quantity的视图并创建{{1}触发视图,将视图上的order_row转换为基表上的instead ofupdate,具体取决于update值。但是,这会为您的代码添加额外的间接层,但仍然会使应用程序流难以遵循。