这里我有两个名为Product table和Sales table的表:
Product table Sales table
P_ID|QTY | |O_ID|QTY |
1 |10 | |1 |5 |
2 |15 |
现在,我试图创建一个带有概念的触发器,每当我在销售表中插入新记录时,Product表应该更新的是基于销售表“数量”的“库存” 代码:
/*---------------------------------------------------------*/
create trigger "KABIL_PRACTICE"."SALES_TRIGGER"
after insert on "KABIL_PRACTICE"."SALES" REFERENCING NEW ROW AS newrow for each row
begin
update "KABIL_PRACTICE"."Inventory" set "Inventory" = "Inventory" - :newrow.QTY
where "P_ID" = :newrow.P_ID ;
end;
/*-----------------------------------------------------------*/
并且我得到了预期的输出。当我在P-ID 1和数量为5的销售表中插入记录时
updated Product table Sales table
P_ID|QTY | |O_ID|QTY |
1 |-1 | |1 |5 |
2 |15 | |1 |6 |
但在这里我还有另一个问题..如果我再次使用P_ID 1
再次将quantity 6
插入销售表中,即销售表数量超过可用库存数量意味着它转为负值......
我只是想亲密的销售订单数量值高于可用的库存数量,它不应该变为负值...是否有任何方法...
我试过这段代码:
create trigger "KABIL_PRACTICE"."SALES_UPDATE_TRIGGER"
before insert on "KABIL_PRACTICE"."SALES" REFERENCING NEW ROW AS newrow for each row
begin
if("Inventory" > :newrow.QTY )
Then
update "KABIL_PRACTICE"."Inventory" set "Inventory" = "Inventory" - :newrow.QTY
where "P_ID" = :newrow.P_ID ;
elseif ("Inventory" < :newrow.QTY )
Then NULL;
delete "KABIL_PRACTICE"."SALES" where "QTY" = 0;
end;
答案 0 :(得分:0)
你在这里遇到的问题是经典问题。通常是两个业务流程&#34; SALES&#34;和&#34;订购完成&#34;是分开的,所以卖东西的行为不会对库存水平产生直接影响。相反,订单履行实际上可以使用其他资源(例如,从其他供应商返回订购或生产更多资源)。这样,销售将从当前库存水平解除耦合。
无论如何,如果你想让它保持简单的依赖关系,那就是&#34;只卖 - 什么 - 现在可用 - &#34;那你需要考虑以下几点:
为了解决第一点,可以再次采用不同的方法。最简单的方法是,只要您决定是否处理订单(和库存交易),就可以锁定您感兴趣的库存记录。
SELECT QTY "KABIL_PRACTICE"."Inventory" WHERE P_ID = :P_ID FOR UPDATE;
此语句将获取相关行的锁定并返回或等待锁定可用,以防另一个会话已经拥有它。
一旦检索到物品的数量,您就可以调用其他业务逻辑(完全,部分或拒绝完成订单)。
这些应用程序路径中的每一个都可以是对必要步骤进行分组的存储过程。
通过COMMIT
事务,锁定将被释放。
作为一般性评论:这不应该作为触发器实现。触发器通常不应该涉及可能导致锁定情况的应用程序路径,以避免系统挂起情况。此外,触发器并不能真正理解语句执行的顺序,这很容易导致不必要的副作用。
存储过程可以为应用程序提供一个界面,使其能够以有意义且安全的方式处理您的数据,而不是触发器。 例如。
程序ProcessOrder
或者:拒绝整个订单。
COMMIT;
然后,您的应用程序可以简单地调用该过程并检索结果数据(例如当前订单数据,状态等),而无需担心表格需要如何更新。