INITIATIVEID
を参照するデータが入力された子テーブルがある場合 Oracleは、親の主キーを変更して孤立した行を作成できないようにすることで、主キーの値を自動的に変更できないようにする必要があります。したがって、たとえば、TPM_INITIATIVES
への外部キー制約を持つ子テーブルがある場合 この子テーブルには、INITIATIVEID
の行があります。 17の場合、INITIATIVEID
を変更することはできません。 TPM_INITIAITVES
の行の 現在の値が17のテーブル。TPM_INITIATIVES
の特定の行を参照する行が子テーブルにない場合 テーブルでは、値を変更できますが、おそらく、関係がない場合、主キーの値を変更することは、定義上、データの整合性の問題を引き起こす可能性がないため、重要ではありません。もちろん、TPM_INITIATIVES
に新しい行を挿入するコードを作成することもできます。 新しいINITIATIVEID
を使用 、古い行を参照する子テーブルのすべての行を新しい行を参照するように変更してから、古い行を変更します。しかし、これは提案されたソリューションのいずれにもとらわれることはありません。
アプリケーションで子テーブルが定義されているが、適切な外部キー制約が宣言されていない場合は、それが問題を解決するための最良の方法です。
そうは言っても、ビューを作成するArnonのソリューションは機能するはずです。テーブルの名前を変更し、既存のテーブルと同じ名前のビューを作成し、(潜在的に)INITIATIVEID
を更新しないビューにINSTEADOFトリガーを定義します。 桁。アプリケーションの他のビットを変更する必要はありません。
テーブルにトリガーを定義することもできます
CREATE TRIGGER trigger_name
BEFORE UPDATE ON TPM_INITIATIVES
FOR EACH ROW
DECLARE
BEGIN
IF( :new.initiativeID != :old.initiativeID )
THEN
RAISE_APPLICATION_ERROR( -20001, 'Sorry Charlie. You can''t update the initiativeID column' );
END IF;
END;
もちろん、誰かがトリガーを無効にして更新を発行する可能性があります。ただし、攻撃者を阻止しようとしているのではなく、バグのあるコードであると想定しています。
ただし、表示されている症状の説明に基づいて、このテーブルの列への変更の履歴をログに記録して、穴を推測して塞ぐのではなく、実際に何が起こっているのかを判断できるようにする方が理にかなっているようです。 -一つ。したがって、たとえば、次のようなことができます
CREATE TABLE TPM_INITIATIVES_HIST (
INITIATIVEID NUMBER NOT NULL,
NAME VARCHAR2(100) NOT NULL,
ACTIVE CHAR(1) NULL,
SORTORDER NUMBER NULL,
SHORTNAME VARCHAR2(100) NULL,
PROJECTTYPEID NUMBER NOT NULL,
OPERATIONTYPE VARCHAR2(1) NOT NULL,
CHANGEUSERNAME VARCHAR2(30),
CHANGEDATE DATE,
COMMENT VARCHAR2(4000)
);
CREATE TRIGGER trigger_name
BEFORE INSERT or UPDATE or DELETE ON TPM_INITIATIVES
FOR EACH ROW
DECLARE
l_comment VARCHAR2(4000);
BEGIN
IF( inserting )
THEN
INSERT INTO tpm_initiatives_hist( INITIATIVEID, NAME, ACTIVE, SORTORDER, SHORTNAME, PROJECTTYPEID,
OPERATIONTYPE, CHANGEUSERNAME, CHANGEDATE )
VALUES( :new.initiativeID, :new.name, :new.active, :new.sortOrder, :new.shortName, :new.projectTypeID,
'I', USER, SYSDATE );
ELSIF( inserting )
THEN
IF( :new.initiativeID != :old.initiativeID )
THEN
l_comment := 'Initiative ID changed from ' || :old.initiativeID || ' to ' || :new.initiativeID;
END IF;
INSERT INTO tpm_initiatives_hist( INITIATIVEID, NAME, ACTIVE, SORTORDER, SHORTNAME, PROJECTTYPEID,
OPERATIONTYPE, CHANGEUSERNAME, CHANGEDATE, COMMENT )
VALUES( :new.initiativeID, :new.name, :new.active, :new.sortOrder, :new.shortName, :new.projectTypeID,
'U', USER, SYSDATE, l_comment );
ELSIF( deleting )
THEN
INSERT INTO tpm_initiatives_hist( INITIATIVEID, NAME, ACTIVE, SORTORDER, SHORTNAME, PROJECTTYPEID,
OPERATIONTYPE, CHANGEUSERNAME, CHANGEDATE )
VALUES( :old.initiativeID, :old.name, :old.active, :old.sortOrder, :old.shortName, :old.projectTypeID,
'D', USER, SYSDATE );
END IF;
END;
次に、TPM_INITIATIVES_HIST
にクエリを実行できます。 時間の経過とともに特定の行に加えられたすべての変更を確認します。したがって、主キーの値が変更されているのか、誰かが非キーフィールドを変更しているだけなのかを確認できます。理想的には、変更の追跡に役立つように履歴テーブルに追加できる追加の列がある場合があります(つまり、V$SESSION
から何かがある可能性があります 役に立つかもしれません。