まず、現在、望ましい動作をしていますが、データベースへの変更が必要になったときに維持するのは簡単ではありません。私は、よりシンプルで、より効率的で、保守しやすいものを探しています (これら 3 つのいずれかを行うものは大歓迎です)。更新を実行すると、現在の行のコピーである履歴行が作成され、現在の行の値が更新されます。その結果、更新前の行の履歴が記録されます。
理由: 私たちは多くの連邦規則に準拠する必要があり、すべての完全な監査履歴を保持するためにこの方法を採用しました。また、いつでもデータベースを見て、物事がどのように見えるかを確認できます (将来の要件) . 同様の理由で、履歴の記録方法を変更することはできません...どのソリューションも、現在のトリガーが作成するデータと同じ結果になる必要があります。
Contact
テーブルの現在のトリガーは次のようになります:
(簡潔にするために不要なフィールドを取り除いています。フィールドの数は重要ではありません)
更新前 (各行):
DECLARE
indexnb number;
BEGIN
:new.date_modified := '31-DEC-9999';
indexnb := STATE_PKG.newCONTACTRows.count + 1;
:new.date_start := sysdate;
:new.version := :old.version + 1;
state_pkg.newCONTACTRows(indexnb).ID := :old.ID;
state_pkg.newCONTACTRows(indexnb).PREFIX := :old.PREFIX;
state_pkg.newCONTACTRows(indexnb).FIRST_NAME := :old.FIRST_NAME;
state_pkg.newCONTACTRows(indexnb).MIDDLE_NAME := :old.MIDDLE_NAME;
state_pkg.newCONTACTRows(indexnb).LAST_NAME := :old.LAST_NAME;
--Audit columns after this
state_pkg.newCONTACTRows(indexnb).OWNER := :old.OWNER;
state_pkg.newCONTACTRows(indexnb).LAST_USER := :old.LAST_USER;
state_pkg.newCONTACTRows(indexnb).DATE_CREATED := :old.DATE_CREATED;
state_pkg.newCONTACTRows(indexnb).DATE_MODIFIED := sysdate;
state_pkg.newCONTACTRows(indexnb).VERSION := :old.VERSION;
state_pkg.newCONTACTRows(indexnb).ENTITY_ID := :old.id;
state_pkg.newCONTACTRows(indexnb).RECORD_STATUS := :old.RECORD_STATUS;
state_pkg.newCONTACTRows(indexnb).DATE_START := :old.DATE_START;
END;
更新前 (すべての行に対して 1 回):
BEGIN
state_pkg.newCONTACTRows := state_pkg.eCONTACTRows;
END;
更新後 (すべての行に対して 1 回):
DECLARE
BEGIN
for i in 1 .. STATE_PKG.newCONTACTRows.COUNT loop
INSERT INTO "CONTACT" (
ID,
PREFIX,
FIRST_NAME,
MIDDLE_NAME,
LAST_NAME,
OWNER,
LAST_USER,
DATE_CREATED,
DATE_MODIFIED,
VERSION,
ENTITY_ID,
RECORD_STATUS,
DATE_START)
VALUES (
CONTACT_SEQ.NEXTVAL,
state_pkg.newCONTACTRows(i).PREFIX,
state_pkg.newCONTACTRows(i).FIRST_NAME,
state_pkg.newCONTACTRows(i).MIDDLE_NAME,
state_pkg.newCONTACTRows(i).LAST_NAME,
state_pkg.newCONTACTRows(i).OWNER,
state_pkg.newCONTACTRows(i).LAST_USER,
state_pkg.newCONTACTRows(i).DATE_CREATED,
state_pkg.newCONTACTRows(i).DATE_MODIFIED,
state_pkg.newCONTACTRows(i).VERSION,
state_pkg.newCONTACTRows(i).ENTITY_ID,
state_pkg.newCONTACTRows(i).RECORD_STATUS,
state_pkg.newCONTACTRows(i).DATE_START
);
end loop;
END;
次のように定義されたパッケージ (トリミングされたフル バージョンは、表ごとにこれをコピーしたものにすぎません):
PACKAGE STATE_PKG IS
TYPE CONTACTArray IS TABLE OF CONTACT%ROWTYPE INDEX BY BINARY_INTEGER;
newCONTACTRows CONTACTArray;
eCONTACTRows CONTACTArray;
END;
現在の結果
結果の履歴サンプルは次のとおりです。
ID First Last Ver Entity_ID Date_Start Date_Modified
1196 John Smith 5 0 12/11/2009 10:20:11 PM 12/31/9999 12:00:00 AM
1201 John Smith 0 1196 12/11/2009 09:35:20 PM 12/11/2009 10:16:49 PM
1203 John Smith 1 1196 12/11/2009 10:16:49 PM 12/11/2009 10:17:07 PM
1205 John Smith 2 1196 12/11/2009 10:17:07 PM 12/11/2009 10:17:19 PM
1207 John Smith 3 1196 12/11/2009 10:17:19 PM 12/11/2009 10:20:00 PM
1209 John Smith 4 1196 12/11/2009 10:20:00 PM 12/11/2009 10:20:11 PM
各履歴レコードには、現在の行の ID である Entity_ID があり、新しいレコードの Date_Start は、最後の履歴行の Date_Modified と一致します。これにより、次のようなクエリを実行できますWhere Entity_ID = :id Or ID = :id And :myDate < Date_Modified And :myDate >= Date_Start
。履歴は で取得できますEntity_ID = :current_id
。
これを行うためのより良いアプローチはありますか? 概念は単純です。行を更新するときに、古い値を挿入して同じテーブルにコピーし、現在の行を更新します...しかし、実際にそれを行うには、もっと簡単な方法をまだ見つけていません。オラクルのより巧妙で賢明な人が、これに対するより良いアプローチを持っていることを願っています。速度はそれほど重要ではありません。ほとんどの Web アプリケーションと同様に、99% 読み取り 1% 書き込みであり、すべての一括操作は挿入であり、履歴を作成しない更新ではありません。
誰かがこれのメンテナンスを簡素化するためのアイデアを持っているなら、私は非常に感謝しています、ありがとう!