oracle - 如何解决这个关于 Oracle 触发器的练习

标签 oracle triggers business-rules

我必须解决这个关于触发器的练习:

Consider the following relational database schema used to represent project information:

Person (ID, Surname, Name, Nationality)

Project (Name, Manager, StartingYear, NumPeopleInvolved, International)

Personnel (Project, PersonID)

Specify the triggers required in Oracle to maintain the following integrity constraints:

a) The number of people involved in a project (attribute NumPeopleInvolved) must be consistent with the number of tuples entered in Personnel for that project

b) If the project is international (the International attribute assumes only two values) then the project must involve at least two people of different nationalities


我对 b) 部分有问题。
我不知道如何处理给定项目没有人参与的情况。如果我尝试插入第一个人,我不能有两个不同国籍的人,因为我只有一个人。
这种情况应该如何处理?
我应该使用语句级触发器吗?我没有使用触发器的经验,所以我仍然没有很好地理解我可以/我不能用一种触发器做什么。
我试过这种方式,但它显然不能正常工作:
CREATE TRIGGER InsertPersonnelInternational
AFTER INSERT ON Personnel
FOR EACH ROW
BEGIN
    SELECT ProjectName
    FROM Personnel INNER JOIN Project
    WHERE PersonID = :new.ID Project = Name

    SELECT International
    FROM Personnel INNER JOIN Project
      ON Project = Name

    SELECT COUNT(*) AS NumPersonnel
    FROM Personnel
    WHERE Project = :new.Project

    IF NumPersonnel >= 1 THEN
    BEGIN
        SELECT COUNT(*) AS NumNationalities
        FROM Personnel INNER JOIN Person
        ON Project = ProjectName
        GROUP BY Nationality

        IF International THEN
            IF NumNationalities = 1 Then
            BEGIN
                raise_application_error(-1)
            END
        ELSE
            IF NumNationalities <> 1 THEN
            BEGIN
                raise_application_error(-1)
            END
        END
    END
END

最佳答案

最好的方法是使用复合触发器。使用复合触发器,我们避免了从 PERSONNEL 上的行级触发器获得的表发生变异的问题。
我们跟踪数组中 DML 语句(插入、更新、删除)中每个受影响行引用的每个项目。在语句的最后我们查询那些项目,看项目是否是国际的,如果是检查其指定人员的国籍。
它可能看起来像这样:

CREATE OR REPLACE TRIGGER international_project_trg
  FOR insert or update or delete ON personnel
    COMPOUND TRIGGER

  -- Global declaration
  type project_t is table of number index by personnel.project%type;
  g_project project_t; 

  BEFORE EACH ROW IS
  BEGIN
    CASE
      -- we don't care about the value here, we just what a set of distinct projects
      WHEN INSERTING THEN
        g_project(:new.project) := 1;
      WHEN UPDATING THEN
        g_project(:new.project) := 1;
      WHEN DELETING THEN
        g_project(:old.project) := 1;
    END CASE;
  END BEFORE EACH ROW;

  AFTER STATEMENT IS
    l_project personnel.project%type;
    l_country_cnt pls_integer;
    l_people_cnt pls_integer; 
  BEGIN
    l_project := g_project.first();
    
    while l_project is not null loop
      select count(distinct ppl.nationality)
             ,count(*) 
       into l_country_cnt
            ,l_people_cnt
       from personnel per
            join project prj on per.project  = prj.name
            join person  ppl on per.personid = ppl.id     
        where per.project = l_project
        and   prj.international = 'Y';
        
        if l_people_cnt <= 1 then
          -- either not international project or only one assigned person
          -- so we don't care
          null;
        elsif l_country_cnt <= 1 then
          raise_application_error(-20999, l_project ||' must have multi-national team membership');  
        end if;
        
        l_project := g_project.next(l_project);
        
    end loop;    
    
  END AFTER STATEMENT;

END international_project_trg;
这是a working demo on db<>fiddle .你可以看到,虽然触发器允许一个国际项目只有一个指定的人,但当我们添加第二个相同国籍的人时,它会引发错误。我们可以通过以特殊顺序插入行来解决这个问题,或者通过插入一组行来更好地解决这个问题。这是应用此类业务规则的问题。
您可以使用相同的方法(在同一个触发器中)检查分配的人员数量是否满足Project.NumPeopleInvolved规则。

注意:复合触发器在 Oracle 11gR1 中出现。

关于oracle - 如何解决这个关于 Oracle 触发器的练习,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64461580/

相关文章:

sql-server - 如何制作仅影响已更新/插入的行的触发器?

java - 用java创建一个简单的规则引擎

javascript - 如何处理流程中的动态规则

delphi - Delphi 中的自动化逻辑

linux - limits.conf 没有生效

java - JDBC 中 hibernate 异常

mysql - 我如何知道我的表是事务表还是锁表?

postgresql - 当表a中的列更新时用于更新表b的Postgres函数

java - Oracle SQL 错误 ORA-00933

oracle - Case 表达式和 bool 值