PL/SQL 触发器未检测到

Posted

技术标签:

【中文标题】PL/SQL 触发器未检测到【英文标题】:PL/SQL Trigger not detecting 【发布时间】:2019-08-31 12:48:27 【问题描述】:

您好,我正在大学学习触发器,我正在尝试实现一个简单的函数来理解逻辑。我正在尝试创建一个触发器,禁止员工同时拥有 4 个以上的项目。 全部编译正确,但是当我通过向员工添加第 5 个项目来测试触发器时,触发器不会检测到它。谁能用我的逻辑解释我做错了什么。

CREATE OR REPLACE TRIGGER MAXPROJECTS 
BEFORE INSERT OR UPDATE
ON WorksOn FOR EACH ROW

DECLARE 
PRAGMA AUTONOMOUS_TRANSACTION;
project_count INT(10);

BEGIN

SELECT COUNT(p#) INTO project_count
FROM WorksOn WHERE e# =:NEW.e#;

IF (project_count > 4) 
THEN RAISE_APPLICATION_ERROR(-20010, 
'employee is already working on 4 
projects.');
END IF;
END;
/

【问题讨论】:

因为AUTONOMOUS_TRANSACTION 杂注。您的触发器(选择语句)只看到提交的数据。如果每个 INSERTUPDATE 语句是一个单独的事务(您需要在每个 INSERTUPDATE 语句之后提交)并且 IF 条件从project_count > Nproject_count > N - 1。但我建议不要在触发器中实现这个逻辑。而是在存储过程 (API) 中实现它 PRAGMA AUTONOMOUS_TRANSACTION = 在这里开始错误。 顺便说一下,这种业务规则是出了名的难以实施,触发器可能不是正确的方法。一方面,如果同一员工同时在五个单独的会议中分配到五个项目怎么办?触发器只看到其他会话的提交数据。 【参考方案1】:

PRAGMA AUTONOMOUS_TRANSACTION 表示您的触发器将在自己的事务中运行。由于是单独的事务,因此无法查看您刚刚插入的未提交数据,因此不会导致插入语句失败。

此编译指示主要用于“副作用”触发器(例如,记录到另一个表),您不希望“副作用”中的失败导致整个操作失败。在此用例中,您期望完全相反,因此不应使用此 pragma。

【讨论】:

【参考方案2】:

这里有几个问题。

首先,我猜你试图在没有 PRAGMA AUTONOMOUS TRANSACTION 的情况下将其设为 ROW 触发器,结果它炸毁了你,所以你搜索了 *** 并发现如何使用这个 PRAGMA 来绕过“mutating table” " 例外 - 这仍然不适合你。

就能够计算分配给员工的项目数量而言,有几种不同的方法可以实现您的目标,但最简单的方法是将其设置为 STATEMENT 触发器而不是 ROW 触发器,这是通过离开来完成的在触发器定义中去掉FOR EACH ROW 子句。语句触发器每个语句只触发一次,而不是为受语句影响的每一行触发一次,并且您无权访问 :NEW 或 :OLD 值 - 但如果您考虑得当,您会意识到您实际上并没有需要这些值。

其次,您已将此设置为 BEFORE 触发器,该触发器在语句执行之前触发,因此该语句所做的更改在触发器中不可见。所以这需要是一个 AFTER 触发器。

以下应该可以满足您的需求

CREATE OR REPLACE TRIGGER WORKSON_BIU_STMT
  AFTER INSERT OR UPDATE
  ON WorksOn
BEGIN
  FOR aRow IN (SELECT e#, COUNT(DISTINCT p#) AS PROJECT_COUNT
                 FROM WorksOn
                 GROUP BY e#)
  LOOP
    DBMS_OUTPUT.PUT_LINE('E#=' || aRow.E# || '  PROJECT_COUNT=' || aRow.PROJECT_COUNT);

    IF aRow.PROJECT_COUNT > 4 THEN
      RAISE_APPLICATION_ERROR(-20010, 'Employee ' || aRow.e# || ' cannot be assigned to ' || aRow.PROJECT_COUNT || ' projects.');
    END IF;
  END LOOP;
END WORKON_BIU_STMT;

dbfiddle here

【讨论】:

鲍勃·贾维斯,非常爱你。

以上是关于PL/SQL 触发器未检测到的主要内容,如果未能解决你的问题,请参考以下文章

oracle中,用pl/sql创建触发器报触发器无效且未通过重新验证

ORA-06510: PL/SQL: 未处理的用户定义异常 [Oracle]

基于变化表中的值在插入之前触发 PL/SQL 触发器

PL/SQL结构

Oracle PL/SQL:将整行从触发器转发到过程

获取 ORA-06502:PL/SQL:数字或值错误:SQL 触发器中的字符到数字转换错误