Om det finns underordnade tabeller fyllda med data som refererar till INITIATIVEID
kolumnen bör Oracle automatiskt göra det svårt att ändra primärnyckelns värde genom att förhindra dig från att skapa föräldralösa rader genom att ändra förälderns primärnyckel. Så, till exempel, om det finns en underordnad tabell som har en främmande nyckel-begränsning till TPM_INITIATIVES
och det finns en rad i denna underordnade tabell med ett INITIATIVEID
av 17 kommer du inte att kunna ändra INITIATIVEID
av raden i TPM_INITIAITVES
tabell vars nuvarande värde är 17. Om det inte finns någon rad i någon underordnad tabell som refererar till den specifika raden i TPM_INITIATIVES
tabell kan du ändra värdet, men förmodligen, om det inte finns några relationer, är det oviktigt att ändra det primära nyckelvärdet eftersom det per definition inte kan orsaka ett dataintegritetsproblem. Naturligtvis kan du ha kod som infogar en ny rad i TPM_INITIATIVES
med ett nytt INITIATIVEID
, ändra alla rader i den underordnade tabellen som hänvisar till den gamla raden för att hänvisa till den nya raden, ändra sedan den gamla raden. Men detta kommer inte att fångas av någon av de föreslagna lösningarna.
Om ditt program har definierat underordnade tabeller men inte deklarerat lämpliga begränsningar för främmande nyckel, skulle det vara det bästa sättet att lösa problemet.
Med det sagt borde Arnons lösning att skapa en vy fungera. Du skulle byta namn på tabellen, skapa en vy med samma namn som den befintliga tabellen och (potentiellt) definiera en INSTEAD OF trigger på vyn som helt enkelt aldrig skulle uppdatera INITIATIVEID
kolumn. Det borde inte kräva ändringar i andra delar av programmet.
Du kan också definiera en trigger på bordet
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;
Någon kan naturligtvis inaktivera triggern och utfärda en uppdatering. Men jag antar att du inte försöker stoppa en angripare, bara en buggig kod.
Baserat på beskrivningen av vilka symtom du ser, verkar det dock vara mer meningsfullt att logga historiken för ändringar av kolumner i den här tabellen så att du faktiskt kan avgöra vad som pågår istället för att gissa och försöka täppa till hål ett -av en. Så du kan till exempel göra något sånt här
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;
Sedan kan du fråga TPM_INITIATIVES_HIST
för att se alla ändringar som har gjorts på en viss rad över tiden. Så du kan se om de primära nyckelvärdena ändras eller om någon bara ändrar icke-nyckelfälten. Helst kan du ha ytterligare kolumner som du kan lägga till i historiktabellen för att hjälpa till att spåra ändringarna (dvs. det kanske finns något från V$SESSION
som kan vara användbart).