我必须解决这个关于触发器的练习:
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/