Oracle 创建删除行的触发器

Oracle 创建删除行的触发器,oracle,plsql,triggers,procedure,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, ); 我想创建一个触发器,当update将数量更改为0(零)->删除此行时 我试过这个: 检查\u订单\u行触发器: 删

我有一张桌子:

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,
);
我想创建一个触发器,当update将数量更改为0(零)->删除此行时

我试过这个:

检查\u订单\u行触发器:

删除\u订单\u行的过程如下:

删除订单行程序:

但当我尝试更新时:

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.
我能做些什么改变吗?或者尝试其他方法来做到这一点

提前谢谢

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

表上的行级触发器通常无法查询同一个表,而不会导致变异表异常。如果确实确定了,可以创建一个包,在该包中创建一个
order\u id
值的集合,创建一个用于初始化集合的before语句触发器,创建一个用
:new.order\u id
填充集合的行级触发器,然后是一个after语句触发器,它遍历集合并调用
delete\u order\u row
。然而,这是一个需要处理的问题。通常,将
数量设置为0的应用程序代码删除该行更有意义。将逻辑放入触发器中,删除应用程序刚刚插入(或更新)的行,通常会导致应用程序流非常难以遵循(部分原因是您永远无法一次看到整个流,您需要不断查看触发器产生的副作用)以及很难理解和调试的bug


如果您决定使用触发器,但不想使用三触发器解决方案,也可以重命名该表,创建一个名为
order\u row
的视图,并在视图上创建一个
而不是
触发器,该视图将视图上的
update
转换为基础表上的
update
delete
,具体取决于
quantity
值。不过,这给代码增加了一层额外的间接寻址,这仍然会使应用程序流难以遵循。

这就是您所说的递归触发器。我不认为Oracle支持。我想知道当
quantity
达到0时删除一行是否会与同一行的并发更新冲突?我觉得这就像是比赛状态,我看不到比赛状态。执行更新的会话必须先锁定行,然后才能进行更新。同一个会话应该能够删除该行,而无需获取任何额外的锁,并且鉴于触发器必须在与
更新
相同的事务上下文中触发,因此在此期间其他会话不能修改该行。您可以通过执行类似于从定义为自治事务的触发器发出delete的操作来创建线程问题。但那是个很糟糕的主意。谢谢你的回复。但是,如果OP同时有两个查询,一个用于将数量减少到0,另一个用于增加数量——取决于它们的处理顺序,如果先处理增加的数量(数量
N
->
N+M
->
M
)。或者,如果要增加的更新是在减少之后处理的,则在删除该行时将失败(quantity
N
->
0
--删除该行,因此在此之后无法更新该行)。这个推理有效吗,还是我遗漏了什么?@SylvainLeroux-你不能让同时的查询更新同一行——一个会话将获得一个锁并首先进行更改,而其他会话将被阻塞。在多用户系统中,始终存在其他会话锁定要更新的行的可能性,或者在您选择该行和修改该行之间该行已发生更改的可能性。在一个会话中添加一个删除或触发器不会有意义地改变这一点。非常感谢@JustinCave为我提供了很多帮助!我希望从Oracle中删除会更容易,但我想我会在更新之前从php代码中删除。:)
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.