【问题标题】:PL/SQL Trigger not detectingPL/SQL 触发器未检测到
【发布时间】: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 = 在这里开始错误。
  • 顺便说一下,这种业务规则是出了名的难以实施,触发器可能不是正确的方法。一方面,如果同一员工同时在五个单独的会议中分配到五个项目怎么办?触发器只看到其他会话的提交数据。

标签: sql oracle plsql database-trigger


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

    这里有几个问题。

    首先,我猜你试图在没有 PRAGMA AUTONOMOUS TRANSACTION 的情况下将其设为 ROW 触发器,结果它炸毁了你,所以你搜索了 StackOverflow 并发现如何使用这个 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

    【讨论】:

    • 鲍勃·贾维斯,非常爱你。
    猜你喜欢
    • 2011-08-06
    • 1970-01-01
    • 2018-04-01
    • 2017-09-14
    • 2021-02-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多