PL/SQL触发器无法在插入后读取表

PL/SQL触发器无法在插入后读取表,sql,database,oracle,plsql,triggers,Sql,Database,Oracle,Plsql,Triggers,我正在做一个小项目,复制一个CVS药房数据库。在学习PL/SQL中的触发器时,我认为创建一个触发器是一个好主意,它可以在商店中购买产品时更新商店的产品库存(事务) 现在为了实现这一点,我必须在productLine_T(交易中的产品正在购买的数量表)上进行后插入,存储transactionID,查找新插入交易的employeeID,从该交易的员工处获取storeID,这样,我就可以按storeID获取相应的库存,以按productLine\T中的orderedQuantity更新该仓库库存中的p

我正在做一个小项目,复制一个CVS药房数据库。在学习PL/SQL中的触发器时,我认为创建一个触发器是一个好主意,它可以在商店中购买产品时更新商店的产品库存(事务)

现在为了实现这一点,我必须在productLine_T(交易中的产品正在购买的数量表)上进行后插入,存储transactionID,查找新插入交易的employeeID,从该交易的员工处获取storeID,这样,我就可以按storeID获取相应的库存,以按productLine\T中的orderedQuantity更新该仓库库存中的productID

创建此触发器后,当我尝试插入productLine\u T时,出现以下错误,如上所述:

Error starting at line 193 in command:
INSERT INTO productLine_T(transactionID, productID, productQuantity, productFinalPrice)
VALUES(00000006, 00000001, 2, 1.50)
Error report:
SQL Error: ORA-04091: table BSEWARDS.PRODUCTLINE_T is mutating, trigger/function may     not see it
ORA-06512: at "BSEWARDS.ONPRODUCTPURCHASED", line 10
ORA-04088: error during execution of trigger 'BSEWARDS.ONPRODUCTPURCHASED'
04091. 00000 -  "table %s.%s is mutating, trigger/function may not see it"
*Cause:    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.
*Action:   Rewrite the trigger (or function) so it does not read that table.
我不明白为什么触发器在插入后不能读入新值?我可以在需要帮助时包括我的ERD和任何其他视觉表示

*触发:*


PL/SQL中的行级触发器不能
从它们所在的表中选择
,而不会导致错误。在您的情况下,我认为您甚至不需要从中选择
,您就不能将其替换为:

SELECT transactionID, productID, productQuantity into transID, prodID, transQty
FROM productLine_T
WHERE productLine_T.transactionID = :new.transactionID;
为此:

transID  := :new.transactionID;
prodID   := :new.productID;
transQty := :new.productQuantity;
第二个问题是触发器中的两个查询都引用了多个表,但您没有指定任何连接条件,这意味着您将获得两个表的连接条件。实际上,您并不关心员工,您只关心商店,因此您最好将这两个查询替换为一个能够获取您所需内容的查询:

SELECT st.storeID INTO stID
FROM Transaction_T trans
INNER JOIN Employee_T emp ON (emp.employeeID = trans.employeeID)
INNER JOIN Store_T st ON (st.storeID = emp.storeID)
WHERE trans.transactionID = transID;
我在这里对您的模式进行了一些猜测,但它可能已经足够接近您了。注意ANSI join语法的使用,它将联接条件(在
ON
子句中)与筛选器谓词(在
WHERE
子句中)巧妙地分开


也值得注意的是,有些人认为使用<代码>选择是不好的形式…进入…
语句,因为如果得到零行或多行,它将引发异常。最好将查询放在游标中,然后从中提取一次。这样,您就知道您将只获得一条记录,通过检查游标属性,您可以轻松地防止零记录。

阅读以下内容:。你可以试试复合触发器:没有复合触发器这是不可能的吗?它应该是一个相对简单的触发器,不应该因为表的变化而中断。很好。。我真的只需要新的价值观,谢谢。我将更改它,看看会发生什么。新列值的语法是“transID:=:new.transactionID”,只是缺少一个半殖民地,修复了上述问题,但现在我收到一个错误,指出“精确获取返回的行数超过请求的行数”。这是否意味着我下面的一个查询得到了不止一个结果?确切地说,行级触发器不能从触发表中选择。语句级触发器可以从触发表中选择(甚至更新)。这属于“在触发器中实现业务逻辑”的范畴。当心!这就是疯狂!我发现触发器最好用于执行内务管理、审计等。一旦你开始在触发器中执行业务规则,你就已经迈出了第一步,走上了一条黑暗的道路,这条路的尽头是一座熏香缭绕的祭坛,狂热的奉献者们在祭坛前低垂着身子,高呼“Cthulhu fhtagn!”,程序员们编写了一万行触发器,它们触发了一个又一个令人发狂的瀑布!当心!(还有,别问我怎么知道…:-)
SELECT st.storeID INTO stID
FROM Transaction_T trans
INNER JOIN Employee_T emp ON (emp.employeeID = trans.employeeID)
INNER JOIN Store_T st ON (st.storeID = emp.storeID)
WHERE trans.transactionID = transID;