简体   繁体   English

PL / SQL触发器无法读取表AFTER INSERT

[英]PL/SQL trigger cannot read table AFTER INSERT

I am doing a small project, replicating a CVS Pharmacy DB. 我正在做一个小项目,复制一个CVS药房数据库。 Learning about triggers in PL/SQL, I thought it would be a good idea to create a trigger that would update the store's inventory of a product when that product is purchased in the store (transaction). 了解PL / SQL中的触发器,我认为创建一个触发器是一个好主意,该触发器会在商店(交易)中购买该产品时更新商店的产品库存。

Now in order to do so, I have to do a AFTER INSERT on productLine_T (the table where a product in the transaction is being purchased with a quantity), store the transactionID, find the employeeID of newly inserted transaction, get storeID from employee of that transaction, which then allows me to get the corresponding inventory by storeID to update the productID in Inventory of that store by the orderedQuantity in productLine_T. 现在为了这样做,我必须在productLine_T上进行AFTER INSERT(使用数量购买交易中的产品的表),存储transactionID,找到新插入事务的employeeID,从员工获取storeID该事务,然后允许我通过storeID获取相应的库存,以通过productLine_T中的orderedQuantity更新该商店的库存中的productID。

After creating this trigger, I am getting the following error when I try inserting into productLine_T, described above: 创建此触发器后,当我尝试插入productLine_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.

I don't understand why the trigger cannot read in the new value AFTER INSERT? 我不明白为什么触发器无法读入新的值后插入? I can include my ERD and any other visual representations needed for help when requested. 我可以包括我的ERD以及在需要时提供帮助所需的任何其他视觉表示。

* Trigger: * * 触发:*

    create or replace 
trigger onProductPurchased
  AFTER INSERT on productLine_T
  for each row
    declare
      transQty productLine_T.productQuantity%type;
      transID productLine_T.transactionID%type;
      prodID productLine_T.productID%type;
      empID Employee_T.employeeID%type;
      stID Store_T.storeID%type;
      --outOfStock exception;
  begin
    --store new transactionID in transID for query
    select transactionID, productID, productQuantity into transID, prodID, transQty
      FROM productLine_T
      WHERE productLine_T.transactionID = :new.transactionID;
    --find store by employee of transactionID to get inventory of store

      -- get employeeID of newly inserted transaction
      select emp.employeeID into empID FROM Employee_T emp, Transaction_T trans
        WHERE trans.transactionID = transID;

      -- get storeID from employee at store who made the transaction
      select st.storeID into stID FROM Store_T st, Employee_T emp
        WHERE emp.employeeID = empID;

      --get inventory by storeID and change inventoryQty based on productID quantity
      update Inventory_T 
        set inventoryQuantity = inventoryQuantity - :new.productQuantity
        WHERE Inventory_T.storeID = stID AND Inventory_T.storeID = prodID;
  end;

Row level triggers in PL/SQL cannot SELECT from the table that they're placed on without causing mutating table errors. PL / SQL中的行级触发器无法从放置它们的表中进行SELECT ,而不会导致表变异 In your case, I don't think you even need to SELECT from it - can't you just replace this: 在你的情况下,我认为你甚至不需要从它中SELECT - 你不能只是替换它:

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

with this: 有了这个:

transID  := :new.transactionID;
prodID   := :new.productID;
transQty := :new.productQuantity;

The second problem you have is that both of the queries in your trigger reference more than one table but you haven't specified any join conditions, which means you'll get the cartesian product of the two tables. 您遇到的第二个问题是触发器中的两个查询都引用了多个表,但您没有指定任何连接条件,这意味着您将获得两个表的笛卡尔积 You don't actually care about the employee, you only care about the store, so you'd be better to replace both queries with a single one that fetches just what you need: 您实际上并不关心员工,您只关心商店,因此您最好用一个只提取所需内容的查询替换这两个查询:

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;

I've made some guesses about your schema here, but it's probably close enough to get you there. 我在这里对你的架构做了一些猜测,但它可能足以让你到达那里。 Note the use of ANSI join syntax, which neatly separates the join conditions (in the ON clause) from the filter predicates (in the WHERE clause). 请注意ANSI连接语法的使用,它巧妙地将连接条件(在ON子句中)与过滤谓词(在WHERE子句中)分开。

It's also worth noting that some people consider it bad form to use a SELECT ... INTO ... statement due to the fact that if you ever got zero rows, or more than one row, it will raise an exception. 值得注意的是,有些人认为使用SELECT ... INTO ...语句是不好的形式,因为如果你有零行或多行,它将引发异常。 It would be better to put the query into a cursor and then fetch from it exactly once. 最好将查询放入游标,然后从中获取一次。 This way you know you will only ever get one record and you can easily protect against zero records by checking the %NOTFOUND cursor attribute. 这样您就知道只会获得一条记录,并且可以通过检查%NOTFOUND游标属性轻松防止零记录。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM