【问题标题】:Plsql: How to write this trigger using statement level trigger?Plsql:如何使用语句级触发器编写此触发器?
【发布时间】:2019-04-05 07:41:09
【问题描述】:

我从昨天开始就一直在尝试解决这个问题,但我不知道如何编写一个工作语句级触发器来完成这项任务。

问题来了:

实施并全面测试一个语句触发器,以验证 遵循一致性约束。

“一个职位需要的技能不能超过 4 个”。

准备好后保存您的 CREATE TRIGGER 语句和所有 SQL 语句 全面测试脚本solution3.sql 中的触发器。综合测试是指触发器必须拒绝违反一致性约束的 SQL 语句,接受不违反一致性约束的 SQL 语句。找出应该测试哪些 SQL 语句是您任务的一部分。每当 SQL 语句违反一致性约束时,触发器必须返回 ORA-... 错误消息。使用过程 RAISE_APPLICATION_ERROR 返回 ORA-... 错误消息。如果 SQL 语句不违反一致性约束,则触发器必须返回 no 消息。

如果你想试试这个问题,这里是数据库文件:https://www.dropbox.com/sh/4dyemye2bpq5hv4/AAAEAmTDELHcgFFhpfRrqHtDa?dl=0

我写的代码给了我一个错误,新旧不能用于表级触发器,我认为如果我将它设为行级触发器,这个函数将起作用,但我需要它作为语句触发器工作。你能告诉我我做错了什么吗?

create or replace trigger checkskillnum
before insert or update of pnumber on sneeded
declare
skillnum number;
begin
select count(*) into skillnum from sneeded where sneeded.pnumber = :new.pnumber;
if skillnum > 3 then
RAISE_APPLICATION_ERROR(-20030,'A position does not need more than 4 skills');
end if;
end;
/

结果应该只允许对那些 Skillnum 小于 4 的语句进行插入或更新。 但现在它符合错误:新旧不能用于表级触发器。

新解决方案:

表需要: select 语句的第一个结果是 4,即使 pnumber 不同,触发器也只会检查该结果。

SQL> select pnumber, count(*) as SKILL_COUNT
  2                   from sneeded
  3                   group by pnumber
  4                   order by COUNT(*) DESC
  5  ;

   PNUMBER SKILL_COUNT
---------- -----------
         1           4
         2           3
         3           3
         7           3
         5           3
         6           1
         4           1

7 rows selected.

新解决方案中的错误:

SQL> insert into sneeded values(1,'fishing',7);
insert into sneeded values(1,'fishing',7)
            *
ERROR at line 1:
ORA-20030: A position does not need more than 4 skills
ORA-06512: at "SYSTEM.CHECKSKILLNUM", line 8
ORA-04088: error during execution of trigger 'SYSTEM.CHECKSKILLNUM'


SQL> insert into sneeded values(2,'fishing',7);
insert into sneeded values(2,'fishing',7)
            *
ERROR at line 1:
ORA-20030: A position does not need more than 4 skills
ORA-06512: at "SYSTEM.CHECKSKILLNUM", line 8
ORA-04088: error during execution of trigger 'SYSTEM.CHECKSKILLNUM'


SQL> insert into sneeded values(4,'fishing',7);
insert into sneeded values(4,'fishing',7)
            *
ERROR at line 1:
ORA-20030: A position does not need more than 4 skills
ORA-06512: at "SYSTEM.CHECKSKILLNUM", line 8
ORA-04088: error during execution of trigger 'SYSTEM.CHECKSKILLNUM'

【问题讨论】:

  • 请发布您的代码,以便人们看到您正在运行的内容。
  • 所有代码都在上面。有什么我想念的吗?
  • 我无法从 Dropbox 下载代码,我相信其他人也处于同样的位置。

标签: oracle plsql database-trigger


【解决方案1】:

语句触发器(没有FOR EACH ROW)不能使用:OLD 和:NEW,因为它无权访问行值。但在这种情况下,您实际上并不需要它们 - 您只需要换个角度思考即可。

你关心的是——语句执行后,有没有人拥有三个以上的技能?所以你需要弄清楚如何找到这些信息。

以下内容应该为您完成:

create or replace trigger checkskillnum
  before insert or update on sneeded
begin
  FOR aRow IN (select pnumber, count(*) as SKILL_COUNT
                 from sneeded 
                 group by pnumber
                 order by COUNT(*) DESC)
  LOOP
    IF aRow.SKILL_COUNT > 3 THEN
      RAISE_APPLICATION_ERROR(-20030, 'A position does not need more than 4 skills');
    END IF;

    EXIT;    -- The first row will have the highest SKILL_COUNT, so only need to  
  END LOOP;  -- check the first row.
end CHECKSKILLNUM;

祝你好运。

【讨论】:

  • 感谢您的回答,这个看起来比我的触发器好得多,并且它没有错误地遵守,但它不能按应有的方式工作。此触发器仅检查仅 pnumber = 1 的最高技能计数。但如果我尝试为技能计数小于 3 的其他 pnumber 插入技能,它仍然会被触发。我希望触发器检查特定 pnumber 的技能计数(正在插入或更新)。
  • 如果上述查询中的第一行不超过 3,那么您知道表中的所有行都符合您的条件,包括刚刚插入/更新的行。
  • 对不起,我还是一无所知。我在上面的答案中添加了错误。
  • 还添加了 sneeded 表,以便您查看导致问题的原因
  • 如果您想检查正在更改的特定 pnumber,您需要使用行触发器 - 但您的分配特别要求您在没有可用信息的情况下使用语句触发器.
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-03-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多