2010-11-17 186 views
1

我在mysql中編寫了一個觸發器,用於檢查一個人是否能夠檢出另一個庫項目。我設置的結帳限制是3.我需要將其轉換爲Oracle觸發器,但存在很多問題。mysql觸發器到oracle觸發器

這裏是我的MySQL代碼:

DELIMITER // 
DROP TRIGGER IF EXISTS library.CheckBorrowsTable// 
CREATE TRIGGER CheckBorrowsTable 
BEFORE INSERT ON library.Borrows 
FOR EACH ROW 
BEGIN 
IF ((SELECT COUNT(*) FROM library.Borrows WHERE libraryID = new.libraryID) >= 3)THEN 
SET new = NULL; 
END IF; 
END// 
DELIMITER ; 

這裏是我的Oracle代碼:

IF((SELECT COUNT(libraryID) FROM Borrows WHERE libraryID = :NEW.libraryID) >= 3) THEN 
:NEW = NULL; 
END IF; 

有我的Oracle代碼,但Oracle快捷版其他部分增加的部分(開始,結束等...)

回答

3

表A上的行級觸發器(即library.borrows)無法查詢表A.如果這樣做,您將得到一個變異表異常(除非您可以保證您將你可以用VALUES子句進行單行插入)。所以這在Oracle中不會被認爲是一種很好的開發實踐。

實現這種要求的最合乎邏輯的方式不是通過觸發器。相反,如果您的應用程序調用存儲過程API,那麼您將擁有一個存儲過程(即CHECK_OUT),該存儲過程首先查詢表以確定個人檢出了多少本書,並且只有當該顧客位於下方時纔將該行插入到BORROWS表中他或她的極限。

第二種方法是將檢出的項目數存儲在單獨的表中。如果你有一個顧客表與NUM_CHECKED_OUT柱和你借用表有一個PATRON_ID指示誰借的書,你的觸發器可以與食客表CHECK約束一起做喜歡

CREATE OR REPLACE TRIGGER CheckBorrowsTable 
    BEFORE INSERT ON library.borrows 
    FOR EACH ROW 
BEGIN 
    UPDATE patrons p 
    SET p.num_checked_out = p.num_checked_out + 1 
    WHERE p.patron_id = :new.patron_id 
END; 

的東西,以確保NUM_CHECKED_OUT永遠不會超過3.

除此之外,使用「三觸發解決方案」解決變異表錯誤是可能的,儘管相當麻煩。

  1. A之前的INSERT語句級 觸發清除的是 您在包創建的集合。
  2. BEFORE INSERT行級觸發器 將 的主鍵(或ROWID)寫入 集合中。
  3. 的AFTER INSERT語句 級觸發器從 讀取數據的收集,查詢表, 並確定是否有任何插件 的違反業務規則。如果他們做了 ,則拋出異常。

然而,正如你可能想象的那樣,這三種觸發器解決方案涉及相當數量的移動部件,所以這不是特別明智的。

你也可以用快速刷新的物化視圖來實現這種事情,但我不認爲這是數據庫快遞版本中的一個選項(儘管我可能會錯誤)。

+2

您應該注意,在多用戶場景中,這將不起作用 - 兩個會話可能會爲同一個贊助人插入行,並且兩個會將贊助人表更新爲相同的值,因爲他們不會看到其他會話的更新。您需要序列化訪問顧客表(例如,'CHECK_OUT'首先鎖定行,更新它,插入書,然後提交(釋放鎖))。 – 2010-11-18 00:59:19