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
杂注。您的触发器(选择语句)只看到提交的数据。如果每个 INSERT
或 UPDATE
语句是一个单独的事务(您需要在每个 INSERT
或 UPDATE
语句之后提交)并且 IF 条件从project_count > N
到 project_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创建触发器报触发器无效且未通过重新验证