Jika ada tabel anak yang diisi dengan data yang mereferensikan INITIATIVEID
kolom, Oracle akan secara otomatis mempersulit untuk mengubah nilai kunci utama dengan mencegah Anda membuat baris yatim piatu dengan mengubah kunci utama induk. Jadi, misalnya, jika ada tabel anak yang memiliki batasan kunci asing ke TPM_INITIATIVES
dan ada baris di tabel anak ini dengan INITIATIVEID
dari 17, Anda tidak akan dapat mengubah INITIATIVEID
dari baris di TPM_INITIAITVES
tabel yang nilainya saat ini adalah 17. Jika tidak ada baris dalam tabel anak mana pun yang merujuk ke baris tertentu di TPM_INITIATIVES
tabel, Anda bisa mengubah nilainya tetapi, mungkin, jika tidak ada hubungan, mengubah nilai kunci utama tidak penting karena menurut definisi tidak dapat menyebabkan masalah integritas data. Tentu saja, Anda dapat memiliki kode yang menyisipkan baris baru ke dalam TPM_INITIATIVES
dengan INITIATIVEID
baru , ubah semua baris di tabel anak yang merujuk ke baris lama untuk merujuk ke baris baru, lalu ubah baris lama. Tapi ini tidak akan terjebak oleh salah satu solusi yang diusulkan.
Jika aplikasi Anda telah mendefinisikan tabel anak tetapi tidak mendeklarasikan batasan kunci asing yang sesuai, itu akan menjadi cara terbaik untuk menyelesaikan masalah.
Karena itu, solusi Arnon untuk membuat tampilan harus berfungsi. Anda akan mengganti nama tabel, membuat tampilan dengan nama yang sama dengan tabel yang ada, dan (berpotensi) menentukan pemicu BUKAN pada tampilan yang tidak akan pernah memperbarui INITIATIVEID
kolom. Itu seharusnya tidak memerlukan perubahan pada bagian lain dari aplikasi.
Anda juga dapat menentukan pemicu di tabel
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;
Seseorang dapat, tentu saja, menonaktifkan pemicu dan mengeluarkan pembaruan. Tapi saya berasumsi Anda tidak mencoba menghentikan penyerang, hanya sepotong kode yang bermasalah.
Namun, berdasarkan deskripsi gejala apa yang Anda lihat, akan lebih masuk akal untuk mencatat riwayat perubahan pada kolom dalam tabel ini sehingga Anda dapat benar-benar menentukan apa yang sedang terjadi daripada menebak dan mencoba memasukkan lubang satu -dengan satu. Jadi, misalnya, Anda bisa melakukan sesuatu seperti ini
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;
Kemudian Anda dapat menanyakan TPM_INITIATIVES_HIST
untuk melihat semua perubahan yang telah dibuat pada baris tertentu dari waktu ke waktu. Jadi, Anda dapat melihat apakah nilai kunci utama berubah atau seseorang hanya mengubah bidang non-kunci. Idealnya, Anda mungkin memiliki kolom tambahan yang dapat Anda tambahkan ke tabel riwayat untuk membantu melacak perubahan (mis. mungkin ada sesuatu dari V$SESSION
yang mungkin berguna).