したがって、IDX_ATS_CALC_END_TIMEという索引を持つ表があります。列はタイムスタンプ値です。この列には、別の列(Interval_duration)が移入または更新されたときに列を自動的に移入するトリガーもあります。取得する理由(ORA-8102「索引キーが見つかりません」)
トリガーは以下の通りです:
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です。
私はこの問題を解決しようと数日間過ごしました。インデックスを再構築しました。インデックスの削除と再作成を試みました。この2つはこの問題の一般的な答えと思われますが、私にとってはうまくいきませんでした。 私は、次を使用してインデックスに分析しました:
ANALYZE INDEX IDX_ATS_CALC_END_TIME VALIDATE STRUCTURE;
をし、それが問題なく帰ってきました。
このエラーを表示せずにこの列を正常に更新することができたのは、トリガーを無効にして更新を実行し、再度トリガーを有効にすることだけでした。これは私にとって実行可能な解決策ではありません。
誰かがこの種の問題に遭遇したことを知りたいと思っています。このエラーを修正するために他にどのような手順をとることができますか?
UPDATE:これは私の前任者によって書かれましたが、基本的にはそれがないすべてが与えられた数値を回しているとに変換
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;
:あなた以下 は、関数pb_util.secondtointerval()のコードを見つけますインターバル値。
ご意見やご提案は大変ありがとうございます。
ありがとうございます。
関数を簡単にすることができます: 'return seconds_in *(interval '1' second);'? –
あなたのインデックス 'IDX_ATS_CALC_END_TIME'の定義は何ですか?それは関数ベースのインデックスですか? –
http://docs.oracle.com/cd/E11882_01/server.112/e17766/e7500.htm#sthref2691これはバグである可能性があることを示しています。 Saurabhの回答は、非決定論的な関数に基づく関数ベースのインデックスで発生する可能性があることを示しています。 –