2012-06-25 29 views
0

的特定情況下,我有創建表的股票觸發變異表中的SQL用於更新

表的架構如下:

create table stock(item_code varchar2(2) primary key, p_qty number(2),s_qty number(2)); 

的觸發如下:

CREATE OR REPLACE TRIGGER TR_STOCK BEFORE UPDATE OF S_QTY ON STOCK FOR EACH ROW 
DECLARE 
    V_P STOCK.P_QTY%TYPE; 
    V_S STOCK.S_QTY%TYPE; 
    V_I VARCHAR2(2); 
BEGIN 
    V_S:=:NEW.S_QTY; 
    V_I:=:NEW.ITEM_CODE; 
    SELECT P_QTY INTO V_P FROM STOCK WHERE ITEM_CODE=V_I; 
    IF V_S>V_P THEN 
     RAISE_APPLICATION_ERROR(-20400,'SOLD QTY CANNOT EXCEED PURCHASED QTY...'); 
    END IF; 
END; 
/

現在,每當我執行更新查詢時,它說該表變異和標誌以下錯誤:

update stock set s_qty=2 where item_code='i4' 
     * 
ERROR at line 1: 
ORA-04091: table HR.STOCK is mutating, trigger/function may not see it 
ORA-06512: at "HR.TR_STOCK", line 8 
ORA-04088: error during execution of trigger 'HR.TR_STOCK' 

這個問題有什麼幫助嗎?

+0

您不能從觸發器中更新的表中進行選擇。這可能表明您的數據模型存在缺陷......雖然似乎沒有必要做這樣的事情。你爲什麼不使用'if'語句。 – Ben

回答

2

有沒有必要查詢STOCK表。簡單地比較:NEW.P_QTY:NEW.S_QTY領域直接

CREATE OR REPLACE TRIGGER TR_STOCK BEFORE UPDATE OF S_QTY ON STOCK FOR EACH ROW 
DECLARE 
BEGIN 
    IF :new.s_qty > :new.p_qty THEN 
     RAISE_APPLICATION_ERROR(-20400,'SOLD QTY CANNOT EXCEED PURCHASED QTY...'); 
    END IF; 
END; 
/
2

你真的應該考慮使用一個數據庫約束來實現這個邏輯,在這種情況下,你不會需要觸發的。

ALTER TABLE hr.stock 
ADD CONSTRAINT stock_ck1 
CHECK (
    s_qty <= p_qty 
) 

觸發器與約束相比有很多缺點:

  • 觸發器不佔現有數據行,如果你的願望的約束可以做到這一點。
  • 一個FOR EACH ROW觸發具有對SQL引擎和每一行,這增加了INSERTUPDATE語句運行的開銷的PL/SQL引擎之間的上下文切換。隨着行數的增加,這會加起來。
  • Oracle可以在優化SQL語句時使用約束(它知道違反約束的WHERE子句永遠不會返回任何行而不需要檢查行)。

如果您使用觸發器來提供錯誤消息,您應該考慮將其移到您的應用程序邏輯中,並將約束作爲安全措施。