【问题标题】:ORA-04082: NEW or OLD references not allowed in table level triggersORA-04082: 表级触发器中不允许使用 NEW 或 OLD 引用
【发布时间】:2013-09-15 11:40:52
【问题描述】:

我有一个名为 per 的表。在 per 表中,我有一个名为“fl1”的字段和另一个名为“fl2”的字段。更新记录时,我想检查“fl1”的值是否发生了变化。如果值发生了变化,请使用“fl1”中的新值更新“fl2”列。

我想出了这个触发器

CREATE OR REPLACE TRIGGER Flag
AFTER INSERT OR UPDATE on per
REFERENCING NEW AS NEW OLD AS OLD
BEGIN
  If :New.fl1 != :Old.fl1 Then
        :New.fl2:= :new.fl1;
  End If;
END;

我在运行时收到“ORA-04082:表级触发器中不允许新或旧引用”

我正在考虑的另一个选项(不确定它是否有效)是简单地用“fl1”的值更新“fl2”的值,而不管“fl1”的值是否发生了变化。

更新

添加了“对于每一行”并将“插入或更新之后”更改为“插入或更新之前”。它正在工作。

CREATE OR REPLACE TRIGGER Flag
BEFORE INSERT OR UPDATE on per
REFERENCING NEW AS NEW OLD AS OLD

FOR EACH ROW
BEGIN
If :New.fl1 != :Old.fl1 Then
   :New.fl2:= :new.fl1;
End If;
END;

【问题讨论】:

  • 如果您有答案,您应该将其发布为作为答案,而不是作为问题的更新。然后,您可以(在强制延迟之后,IIRC)将答案标记为已接受。这让人们知道您还没有在寻找答案。
  • 次要注意 - 错误消息不正确。没有“表级”触发器;如果触发器不是行级触发器,则它仅适用于受 DML 语句影响的行。我总是看到这些被称为“语句级触发器”。错误信息很有趣。

标签: oracle triggers


【解决方案1】:

DML 触发器被定义为表级或行级。

对于表上的每个操作,表级触发器都会触发一次,因此如果您更新 30 行,那么就表触发器而言,这是一个操作。表触发器无法洞察哪些行被修改,但可用于记录执行操作的事实。

在这种情况下,您需要一个行级触发器,它要求在触发器定义中包含“FOR EACH ROW”。如果您不想更改引用新旧行的方式,“REFERENCING”子句是可选的。

http://docs.oracle.com/cd/B28359_01/appdev.111/b28370/triggers.htm#BABCIBBJ

不过,不确定这里练习的目的是什么。您是否考虑过只引用 fl1 而不是 fl2?

【讨论】:

  • 添加了“每行”。请参阅我的原始帖子中的更新。它正在工作。我的代码高效吗?
  • 效率不如不维护两列,其中一列是另一列的副本。是否需要将 fl1 复制到 fl2 中?
  • 在我们实现更新fl2字段的能力之前,这只是一个临时解决方案。
  • David:如果我跳过检查“fl1”是否已更改,而不管“fl1”是否更改,只需更新“fl2”字段会更好吗??
  • 不,但为了更清楚,我想我会将触发器分成两部分:一个用于 INSERT,一个用于 UPDATE OF FL1。插入触发器将始终设置 FL2,仅当值更改时,UPDATE OF FL2 才会设置它。然后,您可以避免测试 NEW != OLD 是否可能会遇到 NULL 值问题。
【解决方案2】:

最终工作代码:

CREATE OR REPLACE TRIGGER Flag
BEFORE INSERT OR UPDATE on per
REFERENCING NEW AS NEW OLD AS OLD

FOR EACH ROW
BEGIN
If :New.fl1 != :Old.fl1 Then
   :New.fl2:= :new.fl1;
End If;
END;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-10-15
    • 2018-12-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-01
    • 1970-01-01
    • 2016-03-21
    相关资源
    最近更新 更多