簡體   English   中英

PL / SQL觸發器無法讀取表AFTER INSERT

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

我正在做一個小項目,復制一個CVS葯房數據庫。 了解PL / SQL中的觸發器,我認為創建一個觸發器是一個好主意,該觸發器會在商店(交易)中購買該產品時更新商店的產品庫存。

現在為了這樣做,我必須在productLine_T上進行AFTER INSERT(使用數量購買交易中的產品的表),存儲transactionID,找到新插入事務的employeeID,從員工獲取storeID該事務,然后允許我通過storeID獲取相應的庫存,以通過productLine_T中的orderedQuantity更新該商店的庫存中的productID。

創建此觸發器后,當我嘗試插入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.

我不明白為什么觸發器無法讀入新的值后插入? 我可以包括我的ERD以及在需要時提供幫助所需的任何其他視覺表示。

* 觸發:*

    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;

PL / SQL中的行級觸發器無法從放置它們的表中進行SELECT ,而不會導致表變異 在你的情況下,我認為你甚至不需要從它中SELECT - 你不能只是替換它:

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連接語法的使用,它巧妙地將連接條件(在ON子句中)與過濾謂詞(在WHERE子句中)分開。

值得注意的是,有些人認為使用SELECT ... INTO ...語句是不好的形式,因為如果你有零行或多行,它將引發異常。 最好將查詢放入游標,然后從中獲取一次。 這樣您就知道只會獲得一條記錄,並且可以通過檢查%NOTFOUND游標屬性輕松防止零記錄。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM