【问题标题】:Attempting to solve mutating table issue with compound trigger尝试使用复合触发器解决变异表问题
【发布时间】:2015-09-23 19:28:27
【问题描述】:

我正在尝试按照Mutating Table Compound Trigger 的说明根据子表的 id 更新父表并避免发生变异表错误。

我需要获取BLATChildren表中当前记录的父ID(BLATranscriptId),然后子记录更新完成后,我需要提取符合我条件的当前计数并对父表 BLATranscript 执行更新。

此错误已解决 - 我的绑定变量“transcriptID”在代码的“AFTER EACH ROW”部分中出现错误。我已经验证了 BLATChildren.BLATranscriptId 存在并且拼写正确。 解决方案 将 AFTER EACH ROW 更改为 AFTER STATEMENT。

新问题 - 触发器正在更新父表中的每条记录,而不仅仅是匹配的父记录。

任何帮助将不胜感激。谢谢。

    CREATE OR REPLACE TRIGGER transcript_after_update
FOR UPDATE of enrollmentStatus,completionDate on blatChildren
COMPOUND TRIGGER
         transcriptID number:=0;
BEFORE EACH ROW IS 
BEGIN
       transcriptID := :new.blaTranscriptid;
END BEFORE EACH ROW;       
AFTER STATEMENT IS
BEGIN
    update BLATranscript SET (enrollmentStatus, completionDate) = (select 'C',sysdate from dual)
    where id in (select blat.id from BLATranscript blat 
    inner join BlendedActivity bla on blat.blendedactivityid=bla.id
    where blat.id=transcriptID and minCompletion<=(
    select count(countForCompletion) as total from blatChildren blac
    inner join BlendedActivityMembership bam on blac.childActivityId=bam.childActivityId
    where completionDate>=sysdate-acceptPrevWork
    and blat.id=transcriptID
    and blac.enrollmentStatus='C'));
END AFTER STATEMENT;
END;   
/

【问题讨论】:

  • 您不能在触发器的任何行级部分引用定义触发器的表。您需要在触发器的语句级部分中执行此操作。您几乎肯定希望您的局部变量是一个集合,而不是一个标量,并且您希望触发器的语句级部分迭代集合的元素。您在触发器的语句级部分中对局部变量的引用不会以冒号开头。只需使用 transcriptID 而不是 :transcriptID(或任何您为收藏命名的名称)。
  • @sstan - 谢谢。这解决了 BIND 变量问题,但是现在它给了我一个关于我试图避免的变异表问题的问题。
  • @JustinCave - 谢谢。我假设通过收集您正在考虑更接近于文档使用的临时表?不过,我有一个心理障碍,因为在我看来,每次更新子记录时它都会更新父表中的每条记录。我显然不是很了解这一点。
  • 文档使用的是集合(特别是嵌套表)而不是临时表。但是,是的,这就是我建议你遵循的。最有可能的是,您希望触发器的行级部分将 :new.transactionID 添加到集合中,然后您希望在您的触发器来确定要更新的行。
  • @JustinCave - 谢谢。我会尝试一下,并在我尝试完全按照示例进行操作后返回并提供更新。

标签: oracle


【解决方案1】:

您需要为每一行部分收集:new.blaTranscriptid int PL/SQL 表
以及将使用此 PL/SQL 表执行更新的语句部分。
喜欢:

CREATE OR REPLACE TRIGGER transcript_after_update
FOR UPDATE of enrollmentStatus,completionDate on blatChildren
COMPOUND TRIGGER
    TYPE transcriptIDs_t  IS TABLE OF blatChildren.blaTranscriptid%TYPE;
    transcriptID transcriptIDs_t := transcriptIDs_t();
BEFORE EACH ROW IS 
BEGIN
    transcriptID.extend;
       transcriptID(transcriptID.count) := :new.blaTranscriptid;
END BEFORE EACH ROW;       
AFTER STATEMENT IS
BEGIN
  FOR i IN 1..transcriptID.COUNT
  LOOP
    update BLATranscript SET (enrollmentStatus, completionDate) = (select 'C',sysdate from dual)
    where id in (select blat.id from BLATranscript blat 
    inner join BlendedActivity bla on blat.blendedactivityid=bla.id
    where blat.id = transcriptID(i) and minCompletion<=(
    select count(countForCompletion) as total from blatChildren blac
    inner join BlendedActivityMembership bam on blac.childActivityId=bam.childActivityId
    where completionDate>=sysdate-acceptPrevWork
    and blat.id=transcriptID(i)
    and blac.enrollmentStatus='C'));
  END LOOP;
END AFTER STATEMENT;
END;   
/

【讨论】:

  • 你是说使用 PL/SQL 表而不是绑定变量?
  • 我发布了触发器示例(但我附近没有 Oracle,因此可能存在一些拼写错误)。 number 类型的变量不是您需要的,因为它只能存储 1 个值,因此如果外部 UPDATE 语句将更新几行,则触发器 UPDATE 语句中只会使用一个最新值。
  • 感谢您的示例。你在你的每一行部分做了一些我不熟悉的东西,所以我需要做一些研究才能理解这一切。非常感谢。在我进行更多研究并尝试后,我会回来。
  • 无论如何,我的主要观点是你需要使用 AFTER STATEMENT 块而不是 AFTER EACH ROW 来查询 blatChildren,否则你会得到 Mutating table 错误。
  • “在每一行之前”部分仅包含将 blatranscriptid 值添加到 PL/SQL 表中
猜你喜欢
  • 2011-01-09
  • 2014-09-20
  • 1970-01-01
  • 2016-05-21
  • 2017-01-10
  • 2023-03-28
  • 2015-09-18
  • 2014-04-01
  • 1970-01-01
相关资源
最近更新 更多