Plsql PL/SQL:检查触发器中的所有行后运行包

Plsql PL/SQL:检查触发器中的所有行后运行包,plsql,triggers,Plsql,Triggers,我有一个库存表,包括预期数量和实际收到数量。比如说inv.q\u ex和inv.q\u rd 表的INSERT在q_ex中为正值,在q_rd中为零,因为它尚未到达。当我检测到q_rd值从0变为其他值时,我想运行一个包,表明它已被接收和存储 在更新和检查每一行之后进行触发器检测很容易,但我不确定如何确保它只运行一次 骨架是: CREATE OR REPLACE TRIGGER example AFTER UPDATE ON inv FOR EACH ROW

我有一个库存表,包括预期数量和实际收到数量。比如说
inv.q\u ex
inv.q\u rd

表的INSERT在q_ex中为正值,在q_rd中为零,因为它尚未到达。当我检测到q_rd值从0变为其他值时,我想运行一个包,表明它已被接收和存储

在更新和检查每一行之后进行触发器检测很容易,但我不确定如何确保它只运行一次

骨架是:

CREATE OR REPLACE TRIGGER example
     AFTER UPDATE ON inv
          FOR EACH ROW
               BEGIN
                    IF :OLD.q_rd = 0 AND :NEW.q_rd > 0 THEN
                         pkg.proc();
                    END IF;
               END;
/
我看到的问题是我只希望它运行一次。我只需要确定何时需要执行它。理想情况下,在满足条件的第一行,我将退出循环(在我已经知道需要执行时继续检查似乎是浪费)并调用我的过程

CREATE OR REPLACE TRIGGER example
     BEFORE UPDATE ON inv
          FOR EACH ROW
               DECLARE
                    shouldExecute BOOLEAN;
               BEGIN
                    IF :OLD.q_rd = 0 AND :NEW.q_rd > 0 THEN
                         shouldExecute := TRUE;
                    END IF;
               END;
     AFTER UPDATE ON inv
          BEGIN
               IF shouldExecute THEN
                    pkg.proc();
               END IF;
          END;
/
我找不到一种方法来“退出”for each并在更新后将其视为正常,因此我尝试在更新前和更新后使用这两种方法。BEFORE部分将检查每一行并更新一个布尔值。AFTER部分将等待该情况发生,如果是真的,则调用该过程

CREATE OR REPLACE TRIGGER example
     BEFORE UPDATE ON inv
          FOR EACH ROW
               DECLARE
                    shouldExecute BOOLEAN;
               BEGIN
                    IF :OLD.q_rd = 0 AND :NEW.q_rd > 0 THEN
                         shouldExecute := TRUE;
                    END IF;
               END;
     AFTER UPDATE ON inv
          BEGIN
               IF shouldExecute THEN
                    pkg.proc();
               END IF;
          END;
/

我怀疑这无论如何都行不通,因为根据语法,它在每一行重新声明布尔变量。我想也许我可以让它成为“全局的”,但不管怎样,由于某种原因,我不能在同一个触发器中添加前后两个触发器(除非我没有进行足够的研究),所以我把它分成了两个触发器。现在的问题是我不能在两个触发器之间共享布尔值。我能分享这个价值吗,还是我完全错了呢?

这里有很多小问题,所以我会尽力回答:)

关于“FOR EACH ROW”,Oracle触发器支持两种不同的触发方法,语句或行。如果您在定义中包含“FOR EACH ROW”,您将得到一个ROW触发器,该触发器在受查询影响的每行触发一次,这就是您在这里想要的。语句级触发器对于每个查询只触发一次。使用行触发器的一个优点是可以使用:OLD和:NEW元变量,这些元变量引用以前的行值和当前行值

正如您所发现的,您不能在同一个触发器中添加前后-您需要将它们分为两个触发器

不幸的是,没有一种简单的方法在两个触发器之间共享布尔变量。最简单的方法可能是创建一个带有公共变量的包,您可以在BEFORE触发器中设置该变量,然后在AFTER触发器中检入该变量

包的外观如下所示:

CREATE OR REPLACE PACKAGE PCKG_DEMO
AS
  shouldExecute BOOLEAN;
END;
/
然后,更新前触发器:

CREATE OR REPLACE TRIGGER beforeexample
     BEFORE UPDATE ON inv
          FOR EACH ROW
               BEGIN
                    IF :OLD.q_rd = 0 AND :NEW.q_rd > 0 THEN
                         PCKG_DEMO.shouldExecute := TRUE;
                    END IF;
               END;
/
CREATE OR REPLACE TRIGGER afterexample
     AFTER UPDATE ON inv
        FOR EACH ROW
          BEGIN
               IF PCKG_DEMO.shouldExecute THEN
                    pkg.proc();
               END IF;
          END;
/
以及更新后触发器:

CREATE OR REPLACE TRIGGER beforeexample
     BEFORE UPDATE ON inv
          FOR EACH ROW
               BEGIN
                    IF :OLD.q_rd = 0 AND :NEW.q_rd > 0 THEN
                         PCKG_DEMO.shouldExecute := TRUE;
                    END IF;
               END;
/
CREATE OR REPLACE TRIGGER afterexample
     AFTER UPDATE ON inv
        FOR EACH ROW
          BEGIN
               IF PCKG_DEMO.shouldExecute THEN
                    pkg.proc();
               END IF;
          END;
/

这有点假代码——我现在没有访问Oracle数据库的权限。您可以阅读更多关于触发器的信息,希望这对您有所帮助

你需要做更多的研究。通过上面的链接,您可以触发对Oracle 9的讨论。我希望你不是真的在使用这个版本;支助于2007年结束。自版本11g起,Oracle提供了“复合触发器”,您可以在语句和行级别的前后触发相同的触发器。复合触发器确实允许在不同调用之间共享变量。

好建议。最后,我将该变量添加到该过程所在的包中。非常感谢。你需要做更多的研究。通过上面的链接,您可以触发对Oracle 9的讨论。我希望你不是真的在使用这个版本;支助于2007年结束。自版本11g起,Oracle提供了“复合触发器”,您可以在语句和行级别的前后触发相同的触发器。复合触发器允许在不同的调用之间共享变量。我已经有一段时间没有使用触发器了。了解复合触发器非常有用!为什么不写下来作为答案呢?