ORA-04082: 表级触发器中不允许使用 NEW 或 OLD 引用
Posted
技术标签:
【中文标题】ORA-04082: 表级触发器中不允许使用 NEW 或 OLD 引用【英文标题】:ORA-04082: NEW or OLD references not allowed in table level triggers 【发布时间】: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 语句影响的行。我总是看到这些被称为“语句级触发器”。错误信息很有趣。 【参考方案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;
【讨论】:
以上是关于ORA-04082: 表级触发器中不允许使用 NEW 或 OLD 引用的主要内容,如果未能解决你的问题,请参考以下文章
Mysql 说:#1422 - 存储函数或触发器中不允许显式或隐式提交