0

我正在尝试使用 PL/SQL 制作图书馆信息娱乐系统。在你们任何人推测之前,是的,这是一项家庭作业,但我已经努力尝试并在足够努力之后才在这里提出问题。

基本上,我有几个表,其中两个是: Issue(Bookid, borrowerid, issuedate, returndate) Borrower(borrowerid, name, status).

表中的状态Borrower可以是'student' or 'faculty'。我必须使用触发器实现一个限制,即student我在任何时间点只能发行 2 本书,并且在任何时间点只能发行faculty3 本书。

我对 PL/SQL 完全陌生。这可能很容易,我知道如何去做。这是我能做的最好的。请帮助我查找设计/编译器错误。

CREATE OR REPLACE TRIGGER trg_maxbooks
AFTER INSERT ON ISSUE
FOR EACH ROW 
DECLARE
    BORROWERCOUNT INTEGER;
    SORF VARCHAR2(20);
BEGIN
    SELECT COUNT(*) INTO BORROWERCOUNT
    FROM ISSUE
    WHERE BORROWER_ID = :NEW.BORROWER_ID;

    SELECT STATUS INTO SORF
    FROM BORROWER
    WHERE BORROWER_ID = :NEW.BORROWER_ID;

    IF ((BORROWERCOUNT=2 AND SORF='STUDENT')
        OR (BORROWERCOUNT=3 AND SORF='FACULTY')) THEN
        ROLLBACK TRANSACTION;
    END IF;
END;
4

2 回答 2

0

这太丑陋了,我不敢相信你被要求做这样的事情。触发器是实现业务逻辑的最糟糕的方式之一。当面对多个用户时,它们通常会彻底失败。它们也很难调试,因为它们具有难以预料的副作用。

例如,在您的示例中,如果两个人同时插入会发生什么?(提示:在他们都提交之前,他们不会看到对方的修改,这是生成损坏数据的好方法:)

此外,您可能知道,您不能在行级触发器内引用表的其他行(这将引发变异错误)。

话虽如此,在您的情况下,您可以使用一个额外的列Borrower来记录借阅的书籍数量。您必须确保触发器正确更新此值。这也将解决多用户问题,因为您知道只有一个会话可以同时更新单行。因此,只有一个人可以同时更新借款人的数量。

这应该可以帮助您使用插入触发器(您还需要一个删除触发器,并且为了安全起见,更新触发器以防有人更新Issue.borrowerid):

CREATE OR REPLACE TRIGGER issue_borrower_trg
   AFTER INSERT ON issue
   FOR EACH ROW
DECLARE
   l_total_borrowed NUMBER;
   l_status borrower.status%type;
BEGIN
   SELECT nvl(total_borrowed, 0) + 1, status
     INTO l_total_borrowed, l_status
     FROM borrower 
    WHERE borrower_id = :new.borrower_id
      FOR UPDATE;
   -- business rule
   IF l_status = 'student' and l_total_borrowed >= 3 
      /* OR faculty */ THEN
      raise_application_error(-20001, 'limit reached!');
   END IF;
   UPDATE borrower 
      SET total_borrowed = l_total_borrowed
    WHERE borrower_id = :new.borrower_id;
END;

更新:上述方法甚至不适用于您的情况,因为您在issue表格中记录了发行日期/归还日期,因此借阅的书籍数量不会随着时间的推移而保持不变。在这种情况下,我会使用表级 POST-DML 触发器。在每个 DML 验证表中的每一行都验证了您的业务规则之后(但它不会很好地扩展,对于可扩展的解决方案,请参阅Tom Kyte 的这篇文章)。

于 2013-10-15T13:47:01.870 回答
0

尝试这样的事情:

CREATE OR REPLACE TRIGGER TRG_MAXBOOKS
    BEFORE INSERT
    ON ISSUE
    FOR EACH ROW
BEGIN
    IF ( :NEW.BORROWERCOUNT > 2
        AND :NEW.SORF = 'STUDENT' )
       OR ( :NEW.BORROWERCOUNT > 3
          AND :NEW.SORF = 'FACULTY' )
    THEN
        RAISE_APPLICATION_ERROR (
                             -20001,
                             'Cannot issue beyond the limit, retry as per the limit' );
    END IF;
END;
/

触发器内不应有提交或回滚。逻辑异常等价于 ROLLBACK

于 2013-10-15T13:31:53.263 回答