PL / SQL触发库信息娱乐系统

时间:2013-10-15 13:20:18

标签: sql plsql triggers

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

基本上,我有几张桌子,其中两张是: Issue(Bookid, borrowerid, issuedate, returndate) Borrower(borrowerid, name, status)

Borrower表中的状态可以是'student' or 'faculty'。我必须使用触发器实施限制,根据student,我可以在任何时间点和每faculty只发行2本书,在任何时间点都可以发行3本书。

我是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;

2 个答案:

答案 0 :(得分: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

答案 1 :(得分: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验证表中的每一行都验证了您的业务规则(但它不能很好地扩展,对于可扩展的解决方案,请参阅this post by Tom Kyte)。