Итак, у меня есть таблица с индексом 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)
Упомянутый индекс является функционирующим индексом. В индексе используется функция sys_extract_utc в столбце calc_end_time.
Я потратил несколько дней, пытаясь решить эту проблему. Я перестроил индекс, я попытался удалить и воссоздать индекс. Эти два кажутся общим ответом на эту проблему, но они не сработали для меня. Я проанализировал индекс, используя следующее:
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;
это было написано моим предшественником, но в основном все, что он делает, это поворачивает заданное числовое значение и преобразует его в значение интервала.
Любая помощь или предложения приветствуются.
Спасибо.