2015-02-24 27 views
0

此觸發器(Oracle 12c)旨在停止插入和更新表(MainTable aka Room)中的行,其中列(價格)大於一個變量。變量的值取決於另一列(類型)。有三種類型(S,D,K),'類型'的最大允許價格分別爲100,150和200。該觸發器通過引用具有兩列和三行的域表(DomainTable又名RoomType),如下[roomTypeCode(S,D,K),maxPrice(100,150,200)]並確保:如何使用Oracle觸發器(和域表)代替檢查約束來強制執行列範圍

.. .IF new MainTable.type ='S',THEN new MainTable.price < DomainTable.maxPrice(S);

... IF new MainTable.type ='D',THEN new MainTable.price < DomainTable.maxPrice(D);

... IF new MainTable.type ='K',THEN new MainTable.price < DomainTable.maxPrice(K);

這是我的嘗試不起作用。


CREATE TRIGGER Room_Type_Price_Range 
    BEFORE INSERT OR UPDATE ON room 
    REFERENCING NEW AS newRec 
    FOR EACH ROW 
    DECLARE 
    SELECT maxPrice INTO singleRmMax FROM RoomType WHERE RoomTypeCode = 'S'; 
    SELECT maxPrice INTO doubleRmMax FROM RoomType WHERE RoomTypeCode = 'D'; 
    SELECT maxPrice INTO kingRmMax FROM RoomType WHERE RoomTypeCode = 'K'; 
    BEGIN 
    IF ( (:newRec.type = 'S' AND :newRec.price > singleRmMax) 
     OR (:newRec.type = 'D' AND :newRec.price > doubleRmMax) 
     OR (:newRec.type = 'K' AND :newRec.price > kingRmMax) 
     ) 
     RAISE_APPLICATION_ERROR(-20001, 'Price constraint violated. 
      \nCannot Insert/Update in this table.'); 
    END; 

我的錯誤信息:


04098. 00000 - "trigger '%s.%s' is invalid and failed re-validation" 
*Cause: A trigger was attempted to be retrieved for execution and was 
      found to be invalid. This also means that compilation/authorization 
      failed for the trigger. 
*Action: Options are to resolve the compilation/authorization errors, 
      disable the trigger, or drop the trigger. 

感謝您的幫助!

+2

你在'DECLARE'部分有'SELECT's。 – 2015-02-24 02:14:04

+1

在使用觸發器之前,編譯它並檢查它是否有效。 – Alfabravo 2015-02-24 07:05:24

+1

編譯後,使用'show errors'命令(或SQL Developer編譯器日誌)查看遇到的實際問題;或者查詢你的對象名稱的'user_errors'視圖。 – 2015-02-24 09:11:41

回答

2

當您創建觸發器時,您會看到類似'編譯時出現警告'或'錯誤:檢查編譯器日誌'的消息。此時,您可以執行show errors以查看編譯失敗的原因,或查看SQL Developer的編譯器日誌窗口。

當您插入或更新the invalid trigger is automatically recompiled,但由於它仍然無效,您會收到ORA-04098錯誤。你仍然可以看到什麼是錯的通過查詢user_errors觀點:

select line, position, text 
from user_errors 
where type = 'TRIGGER' 
and name = 'ROOM_TYPE_PRICE_RANGE' 
order by sequence; 

與您的代碼中給出了三個錯誤;只顯示每個的第一行:

LINE POSITION TEXT 
---- -------- ------------------------------------------------------------------------------------------------- 
    2  5 PLS-00103: Encountered the symbol "SELECT" when expecting one of the following: 
    10  9 PLS-00103: Encountered the symbol "RAISE_APPLICATION_ERROR" when expecting one of the following: 
    11  50 PLS-00103: Encountered the symbol ";" when expecting one of the following: 

正如大衛·費伯在評論中指出,第一個錯誤是因爲你在你的聲明部分的select語句;也許在這一點上審查the structure of a subprogram將是有用的。

第二個錯誤是因爲您的IF沒有THEN關鍵字,第三個錯誤是因爲您沒有END IF。只是清理你必須正確地申報和填充的變量是什麼,你會得到這樣的:

DECLARE 
    singleRmMax RoomType.MaxPrice%TYPE; 
    doubleRmMax RoomType.MaxPrice%TYPE; 
    kingRmMax RoomType.MaxPrice%TYPE; 
BEGIN 
    SELECT maxPrice INTO singleRmMax FROM RoomType WHERE RoomTypeCode = 'S'; 
    SELECT maxPrice INTO doubleRmMax FROM RoomType WHERE RoomTypeCode = 'D'; 
    SELECT maxPrice INTO kingRmMax FROM RoomType WHERE RoomTypeCode = 'K'; 

    IF ( (:newRec.type = 'S' AND :newRec.price > singleRmMax) 
    OR (:newRec.type = 'D' AND :newRec.price > doubleRmMax) 
    OR (:newRec.type = 'K' AND :newRec.price > kingRmMax) 
    ) THEN 
    RAISE_APPLICATION_ERROR(-20001, 'Price constraint violated. 
     \nCannot Insert/Update in this table.'); 
    END IF; 
END; 

你並不真正需要三個變量,雖然,你可以查詢你感興趣的房型:

DECLARE 
    roomTypeMax RoomType.MaxPrice%TYPE; 
BEGIN 
    SELECT maxPrice INTO roomTypeMax 
    FROM RoomType 
    WHERE RoomTypeCode = :newRec.type; 

    IF :newRec.price > roomTypeMax THEN 
    RAISE_APPLICATION_ERROR(-20001, 
     'Price constraint violated. Cannot Insert/Update in this table.'); 
    END IF; 
END; 

我也採取了\n出來的,不管用什麼插件可能把那兩個文字字符,而不是換行的錯誤消息。

您可能還想考慮捕獲no_data_found並引發您自己的例外情況,因爲這會表明新房型不存在,因此無論如何都無效。

+0

非常感謝Alex! – stacker 2015-02-24 16:53:52

+1

其實,如果你要出門去查詢表格,不妨也可以拿它來進行比較。 '從RootType中選擇count(*)到roomCount,其中RoomTypeCode =:newRec.Type和MaxPrice> =:newRec.price;'。這樣,返回零意味着價格超過了未定義類型代碼的最大值*或*。 「這或那是問題」錯誤信息是好的。 – TommCatt 2015-02-25 17:42:01