我在 mysql 中编写了一个触发器,用于检查一个人是否能够 checkout 另一个图书馆项目。我设置的结帐限制是 3。我需要将其转换为 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 快捷版添加了这些部分(开始、结束等...)
最佳答案
表 A 上的行级触发器(即 library.borrows)无法查询表 A。如果你这样做,你将得到一个变异表异常(除非你可以保证你只会做单行插入VALUES 子句)。因此,这在 Oracle 中不会被视为良好的开发实践。
实现这种要求的最合乎逻辑的方法不是通过触发器。相反,如果您的应用程序调用存储过程 API,您将拥有一个存储过程(即 CHECK_OUT),该存储过程首先查询该表以确定个人已借出多少本书,并且仅当赞助人在下方时才将该行插入到 BORROWS 表中他或她的极限。
第二种方法是将 checkout 的项目数存储在单独的表中。如果您有一个带有 NUM_CHECKED_OUT 列的 PATRONS 表,并且您的 BORROWS 表有一个 PATRON_ID 来指示谁借了这本书,您的触发器可以执行类似的操作
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;
以及 PATRONS 表上的 CHECK 约束以确保 NUM_CHECKED_OUT 永远不会超过 3。
除此之外,可以使用“三触发器解决方案”来解决变异表错误,尽管相当麻烦。
- BEFORE INSERT 语句级别 触发器清除一个集合 你已经创建了一个包。
- 一个 BEFORE INSERT 行级触发器 写入主键(或 ROWID) 被修改成的行 收藏。
- 一个 AFTER INSERT 语句 电平触发器从中读取数据 集合,查询表, 并确定是否有任何插入 违反了商业规则。如果 他们做到了,抛出异常。
然而,正如您可能想象的那样,三触发器解决方案涉及相当多的移动部件,因此并不是特别可取。
您也可以使用可快速刷新的实体化 View 来实现此类操作,但我认为这不是数据库快速版中的一个选项(尽管我对此可能是错误的)。
关于sql - mysql 触发器到 oracle 触发器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4210073/