Ако има дъщерни таблици, попълнени с данни, които препращат към INITIATIVEID
колона, Oracle трябва автоматично да затрудни промяната на стойността на първичния ключ, като ви попречи да създавате осиротели редове чрез промяна на първичния ключ на родителя. Така например, ако има дъщерна таблица, която има ограничение за външен ключ към TPM_INITIATIVES
и има ред в тази дъщерна таблица с INITIATIVEID
от 17, няма да можете да промените INITIATIVEID
от реда в TPM_INITIAITVES
таблица, чиято текуща стойност е 17. Ако няма ред в нито една дъщерна таблица, който препраща към конкретния ред в TPM_INITIATIVES
можете да промените стойността, но вероятно, ако няма връзки, промяната на стойността на първичния ключ е маловажна, тъй като по дефиниция не може да причини проблем с целостта на данните. Разбира се, можете да имате код, който вмъква нов ред в TPM_INITIATIVES
с нов INITIATIVEID
, променете всички редове в дъщерната таблица, които препращат към стария ред, за да препращат към новия ред, след което модифицирайте стария ред. Но това няма да бъде уловено от нито едно от предложените решения.
Ако приложението ви е дефинирало дъщерни таблици, но не е декларирало подходящите ограничения на външния ключ, това би бил най-добрият начин за разрешаване на проблема.
Като се има предвид това, решението на Arnon за създаване на изглед трябва да работи. Ще преименувате таблицата, ще създадете изглед със същото име като съществуващата таблица и (евентуално) ще дефинирате ВМЕСТО задействане на изгледа, който просто никога няма да актуализира INITIATIVEID
колона. Това не трябва да изисква промени в други части на приложението.
Можете също така да дефинирате тригер в таблицата
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
това може да е полезно).