Pokud jsou podřízené tabulky naplněny daty, které odkazují na INITIATIVEID
Oracle by měl automaticky ztížit změnu hodnoty primárního klíče tím, že vám zabrání ve vytváření osiřelých řádků změnou primárního klíče rodiče. Pokud tedy například existuje podřízená tabulka, která má omezení cizího klíče na TPM_INITIATIVES
a v této podřízené tabulce je řádek s INITIATIVEID
ze 17, nebudete moci změnit INITIATIVEID
řádku v TPM_INITIAITVES
tabulka, jejíž aktuální hodnota je 17. Pokud v žádné podřízené tabulce není žádný řádek, který odkazuje na konkrétní řádek v TPM_INITIATIVES
v tabulce, můžete změnit hodnotu, ale pravděpodobně, pokud neexistují žádné vztahy, je změna hodnoty primárního klíče nedůležitá, protože podle definice nemůže způsobit problém s integritou dat. Samozřejmě můžete mít kód, který vloží nový řádek do TPM_INITIATIVES
s novým INITIATIVEID
, změňte všechny řádky v podřízené tabulce, které odkazují na starý řádek, aby odkazovaly na nový řádek, a poté upravte starý řádek. To však nebude chyceno žádným z navrhovaných řešení.
Pokud vaše aplikace definovala podřízené tabulky, ale nedeklarovala příslušná omezení cizího klíče, byl by to nejlepší způsob, jak problém vyřešit.
Jak již bylo řečeno, Arnonovo řešení vytvoření pohledu by mělo fungovat. Přejmenovali byste tabulku, vytvořili pohled se stejným názvem jako stávající tabulka a (potenciálně) definovali MÍSTO spouštěče v pohledu, který by jednoduše nikdy neaktualizoval INITIATIVEID
sloupec. To by nemělo vyžadovat změny jiných částí aplikace.
Můžete také definovat spouštěč na stole
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ěkdo by samozřejmě mohl spoušť deaktivovat a vydat aktualizaci. Ale předpokládám, že se nesnažíte zastavit útočníka, jen zabugovaný kus kódu.
Na základě popisu příznaků, které vidíte, by se však zdálo smysluplnější zaznamenat historii změn sloupců v této tabulce, abyste mohli skutečně určit, co se děje, než hádat a snažit se zacpat díry. -po jednom. Takže byste mohli udělat například něco takového
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;
Poté můžete zadat dotaz na TPM_INITIATIVES_HIST
zobrazit všechny změny, které byly v průběhu času provedeny na konkrétním řádku. Můžete tedy vidět, zda se mění hodnoty primárního klíče nebo zda někdo pouze mění neklíčová pole. V ideálním případě můžete mít další sloupce, které můžete přidat do tabulky historie, abyste pomohli sledovat změny (tj. možná existuje něco z V$SESSION
to by mohlo být užitečné).