2010-11-17 159 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