sql - 触发器计数行给出 ORA-04091:表正在变异,触发器/函数可能看不到它
问题描述
更新表格时出现此错误
UPDATE "Username"."EMPPROJECT"
SET ENDDATE = TO_DATE('2016-09-11 00:00:00', 'YYYY-MM-DD HH24:MI:SS')
WHERE ROWID = 'AAF+8XAAEAAGBIGAAB'
AND ORA_ROWSCN = '537035617'
保存对表“用户名”的更改时出错。“EMPPROJECT”:第 8 行:
ORA-04091:表 Username.EMPPROJECT 正在变异,触发器/函数可能看不到它 ORA-06512:在“Username.CHECKOVERLAPDATEUPDATE”,第 4 行
ORA-04088 :执行触发器“Username.CHECKOVERLAPDATEUPDATE”时出错
触发器定义如下:
create or replace trigger checkOverlapDateUpdate
before Update on EmpProject
for each row
declare
countOfOverlap integer;
begin
select count(*)
into countOfOverlap
from EmpProject EP
where isOverlapping(:new.startDate, :new.endDate, startDate, endDate) = 1
and EP.EmpID = :new.EmpId;
if countOfOverlap > 0
then
RAISE_APPLICATION_ERROR(-00000, 'Overlapping Insertion Dates');
rollback;
end if;
end;
解决方案
Oracle 在这里试图告诉你的是:
- 更新可以跨越多行。
- 但是,您的触发器会查看单行更新 (
for each row
)。 - 由于多行更新语句的单行更新以任意顺序发生,Oracle 无法保证与触发器中的子查询一致、确定的结果。
例如:
update empproject set startdate = startdate + 100, enddate = enddate + 100;
应该不成问题,因为所有日期范围都会转移相同的天数。但是,在更新第一行时,单独看这个,可能会发生冲突,因为其他行还没有改变。表中甚至可能只有两行中间情况会导致日期范围重叠。然后它会突然取决于 Oracle 为更新首先选择的两行中的哪一行。在一种情况下,更新运行时不会出错,在另一种情况下,它会崩溃。一个不确定的结果,这当然是不允许的。
解决方案是在完成更新后检查行。
您可以编写一个AFTER UPDATE
语句触发器(即AFTER UPDATE ON EmpProject
没有FOR EACH ROW
)并将表的每一行与所有其他行进行比较。在一张大桌子上,这可能非常昂贵。
首选方法是编写复合触发器。此触发器将有一个用于更改行(或其键)的数组。在触发器AFTER EACH ROW
部分,您需要将行添加到数组中,在触发器AFTER STATEMENT
部分,您将检查每一行的重叠范围。
此处描述了复合触发器: https ://docs.oracle.com/cd/B28359_01/appdev.111/b28370/triggers.htm#LNPLS2005
推荐阅读
- java - 如何在这个位置找到特定的文本位置(坐标)和drawImage?
- gitlab - 当命令失败时,如何检查 GitLab 运行器中使用了哪个图像?
- java - 用户在 Quiz App 中获得 1 分后分数不会增加。我该如何解决?
- c# - unity Time.timeScale = 0 不会冻结整个场景
- drupal - 对 Drupal 的 Axios 身份验证请求 - invalid_grant
- java - 升级到版本后的 EasyImage 问题。3.0.1
- php - 循环 JSON 图像 - 关于高级自定义字段
- javascript - 如何在Vue中根据选择更改输入的占位符
- accounting - 精确在线 - 是否可以明确匹配 GeneralJournalEntry 和 BankEntry 单个条目行?
- azure - 使用 kubectl 执行 CURL