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提供了“复合触发器”,您可以在语句和行级别的前后触发相同的触发器。复合触发器允许在不同的调用之间共享变量。我已经有一段时间没有使用触发器了。了解复合触发器非常有用!为什么不写下来作为答案呢?