创建删除行的触发器

Create trigger that deletes rows

所以我有这个 table:

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 trigger:

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 procedure:

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.

我可以做些什么改变?或者尝试其他选项来做到这一点?

提前致谢!

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

table 上的行级触发器通常无法在不导致变异 table 异常的情况下查询相同的 table。如果你真的下定决心,你可以创建一个包,在该包中创建一个 order_id 值的集合,创建一个初始化集合的 before 语句触发器,创建一个行级触发器,用 :new.order_id,然后是遍历集合并调用 delete_order_row 的 after 语句触发器。然而,这需要处理很多动人的事情。对于将 quantity 设置为 0 的应用程序代码来说,删除该行通常更有意义。将逻辑放入删除应用程序刚刚插入(或更新)的行的触发器中通常会导致应用程序流程非常难以遵循(部分原因是您永远无法立即看到整个流程,您一直在寻找触发器正在产生什么副作用)和很难理解和调试的错误。

如果您决定使用触发器并且不想使用三触发器解决方案,您还可以重命名 table,创建一个名为 order_row 的视图,然后在视图上创建一个 instead of 触发器,根据 quantity 值。不过,这会为您的代码添加一个额外的间接层,而且它仍然会使应用程序流程难以遵循。