所以我有一个索引名为 IDX_ATS_CALC_END_TIME 的表。该列是一个时间戳值。此列还有一个触发器,当填充或更新另一列 (Interval_duration) 时会自动填充该列。
触发器如下:
TRIGGER "DATAMART"."TRG_ATS_CALC_END_TIME"
BEFORE INSERT OR UPDATE OF INTERVAL_DURATION ON DATAMART.AGG_TIME_SUMMARY
FOR EACH ROW
DECLARE
BEGIN
IF :New.INTERVAL_DURATION > 0 THEN
:New.calc_end_time := :New.start_date_time + pb_util.secondtointerval(:New.INTERVAL_DURATION);
ELSE
:NEW.CALC_END_TIME := :New.start_date_time;
END IF;
EXCEPTION
WHEN OTHERS THEN
pb_util.logdata(1, 'TRG_ATS_CALC_END_TIME', 'Exception Thrown in interval: ' || :New.Interval_DURATION, SQLERRM || ' stack: ' || dbms_utility.format_error_backtrace);
END TRG_ATS_CALC_END_TIME;
最初填充我的表时,没有问题。我的问题是,当我去对表执行插入/更新并尝试通过直接更改列或仅更新 interval_duration 列来修改此列时,我抛出了这个错误:
ORA-08102: 找不到索引键,obj# 97523,文件 4,块 244 (2)
提到的索引是一个基于函数的索引。索引上使用的函数是 calc_end_time 列上的 sys_extract_utc。
我花了几天时间试图解决这个问题。我已经重建了索引,我尝试过删除并重新创建索引。这两个似乎是这个问题的常见答案,但它们对我不起作用。我使用以下方法分析了索引:
ANALYZE INDEX IDX_ATS_CALC_END_TIME VALIDATE STRUCTURE;
它回来时没有任何问题。
我唯一能够成功更新此列而不会出现此错误的方法是禁用触发器,执行更新,然后再次启用触发器。这对我来说不是一个可行的解决方案。
所以我想知道是否有人遇到过这种类型的问题,以及我可以尝试哪些其他步骤来解决这个错误。
更新: 您将在下面找到函数 pb_util.secondtointerval() 代码:
FUNCTION SecondToInterval
(Seconds_IN NUMBER
)
RETURN CONST.PBInterval
IS
sec NUMBER(20, 9);
days NUMBER;
hours NUMBER;
minutes NUMBER;
seconds NUMBER(20, 9);
IntervalAsText NVARCHAR2(32);
ReturnInterval INTERVAL DAY(9) TO SECOND(9);
begin
sec := NVL(Seconds_IN, 0);
days := trunc(sec/(24*60*60));
sec := sec - days*24*60*60;
hours := trunc(sec/(60*60));
sec := sec - hours*60*60;
minutes := trunc(sec/60);
sec := sec - minutes*60;
seconds := trunc(sec);
sec := sec - seconds;
sec := trunc(1000000000*sec);
IntervalAsText := cast(days as nvarchar2)
|| ' ' || cast(hours as nvarchar2)
|| ':' || substr('00' || cast(minutes as nvarchar2), -2, 2)
|| ':' || substr('00' || cast(seconds as nvarchar2), -2, 2)
|| '.' || substr('000000000' || cast(sec as nvarchar2), -9, 9);
--dbms_output.put_line(intervalastext);
ReturnInterval := TO_DSInterval(IntervalAsText);
--ReturnInterval := TO_DSInterval('999999999 23:59:59.999999999');
--dbms_output.put_line(ReturnInterval);
RETURN ReturnInterval;
EXCEPTION
WHEN OTHERS THEN
pb_util.logdata(1, 'PB_UTIL.SecondToInterval', 'ERROR(99A): ', intervalastext);
dbms_output.put_line(intervalastext);
RAISE;
end SecondToInterval;
这是我的前任写的,但基本上它所做的只是将给定的数值转换为间隔值。
非常感谢任何帮助或建议。
谢谢你。