Als er onderliggende tabellen zijn gevuld met gegevens die verwijzen naar de INITIATIVEID
kolom, zou Oracle het automatisch moeilijk moeten maken om de waarde van de primaire sleutel te wijzigen door te voorkomen dat u weesrijen maakt door de primaire sleutel van de bovenliggende sleutel te wijzigen. Dus als er bijvoorbeeld een onderliggende tabel is met een externe sleutelbeperking voor TPM_INITIATIVES
en er is een rij in deze onderliggende tabel met een INITIATIVEID
van 17, kunt u de INITIATIVEID
. niet wijzigen van de rij in de TPM_INITIAITVES
tabel waarvan de huidige waarde 17 is. Als er geen rij is in een onderliggende tabel die verwijst naar de specifieke rij in de TPM_INITIATIVES
tabel, kunt u de waarde wijzigen, maar vermoedelijk, als er geen relaties zijn, is het wijzigen van de primaire sleutelwaarde onbelangrijk, omdat dit per definitie geen gegevensintegriteitsprobleem kan veroorzaken. U kunt natuurlijk code hebben die een nieuwe rij invoegt in TPM_INITIATIVES
met een nieuwe INITIATIVEID
, verander alle rijen in de onderliggende tabel die naar de oude rij verwijzen om naar de nieuwe rij te verwijzen en wijzig vervolgens de oude rij. Maar dit zal niet worden gevangen door een van de voorgestelde oplossingen.
Als uw toepassing onderliggende tabellen heeft gedefinieerd, maar niet de juiste externe-sleutelbeperkingen heeft aangegeven, is dat de beste manier om het probleem op te lossen.
Dat gezegd hebbende, zou Arnons oplossing voor het creëren van een weergave moeten werken. U zou de tabel een andere naam geven, een weergave maken met dezelfde naam als de bestaande tabel en (mogelijk) een INSTEAD OF-trigger definiëren voor de weergave die simpelweg nooit de INITIATIVEID
zou bijwerken kolom. Dat zou geen wijzigingen in andere delen van de applicatie moeten vereisen.
Je zou ook een trigger op de tafel kunnen definiëren
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;
Iemand zou natuurlijk de trigger kunnen uitschakelen en een update kunnen uitgeven. Maar ik neem aan dat je niet probeert een aanvaller te stoppen, maar alleen een stukje code met fouten.
Op basis van de beschrijving van de symptomen die u ziet, lijkt het echter logischer om de geschiedenis van wijzigingen in kolommen in deze tabel te loggen, zodat u daadwerkelijk kunt bepalen wat er aan de hand is in plaats van te raden en gaten te dichten. -bij een. Je zou bijvoorbeeld zoiets als dit kunnen doen
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;
Vervolgens kunt u TPM_INITIATIVES_HIST
. opvragen om alle wijzigingen te zien die in de loop van de tijd in een bepaalde rij zijn aangebracht. U kunt dus zien of de primaire sleutelwaarden veranderen of dat iemand alleen de niet-sleutelvelden wijzigt. In het ideale geval heeft u misschien extra kolommen die u aan de geschiedenistabel kunt toevoegen om de wijzigingen bij te houden (d.w.z. misschien is er iets van V$SESSION
dat kan handig zijn).