2013-04-15 46 views
0

我正在做一個小項目,複製CVS Pharmacy DB。在PL/SQL中學習觸發器時,我認爲創建一個觸發器是一個好主意,當產品在商店(事務)中購買時,該觸發器將更新商店的產品庫存。PL/SQL觸發器無法讀取表AFTER INSERT

現在爲了做到這一點,我必須在productLine_T上進行AFTER INSERT(在交易中的產品正在購買一定數量的表),存儲transactionID,找到新插入的transaction的employeeID,get該交易的員工的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; 
+0

閱讀此:http://docs.oracle.com/cd/E11882_01/appdev.112/e25519/triggers.htm#LNPLS759。你可以嘗試複合觸發器:http://docs.oracle.com/cd/E11882_01/appdev.112/e25519/triggers.htm#LNPLS743 – Art

+0

這是不可能的,但沒有複合觸發器呢?這應該是一個相對簡單的觸發器,不應該中斷與變異表.. –

回答

2

行級從表PL/SQL不能SELECT觸發他們放在而不引起mutating table錯誤。與此

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

: - 在你的情況,我不認爲你甚至需要SELECT從它你就不能更換此

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

你的第二個問題是,無論是在您的觸發器中的查詢引用多個表格,但您沒有指定任何連接條件,這意味着您將獲得兩個表格中的cartesian product。其實你不關心員工,你只關心商店,所以你最好有一個單一的一個獲取什麼您需要更換兩種查詢:

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遊標屬性輕鬆地防止零記錄。

+0

偉大的一點..我真的只需要新的價值觀,謝謝。我會改變它,看看會發生什麼。 –

+0

新列值的語法是「transID:=:new」。TRANSACTIONID」,只是缺少一個分號 –

+0

我固定以上,但現在我得到一個錯誤,指出‘精確取大於行’的請求數量更多的回報。這是否意味着我下面的查詢之一是越來越多一個結果? –