Se sono presenti tabelle figlio popolate con dati che fanno riferimento a INITIATIVEID
colonna, Oracle dovrebbe rendere automaticamente difficile la modifica del valore della chiave primaria impedendo la creazione di righe orfane modificando la chiave primaria del genitore. Quindi, ad esempio, se esiste una tabella figlio che ha un vincolo di chiave esterna su TPM_INITIATIVES
e c'è una riga in questa tabella figlio con un INITIATIVEID
di 17, non potrai modificare il INITIATIVEID
della riga nel TPM_INITIAITVES
tabella il cui valore corrente è 17. Se non è presente alcuna riga in nessuna tabella figlio che fa riferimento alla riga particolare in TPM_INITIATIVES
tabella, è possibile modificare il valore ma, presumibilmente, se non ci sono relazioni, la modifica del valore della chiave primaria non è importante poiché, per definizione, non può causare un problema di integrità dei dati. Ovviamente potresti avere un codice che inserisce una nuova riga in TPM_INITIATIVES
con un nuovo INITIATIVEID
, cambia tutte le righe nella tabella figlio che fanno riferimento alla vecchia riga per fare riferimento alla nuova riga, quindi modifica la vecchia riga. Ma questo non sarà intrappolato da nessuna delle soluzioni proposte.
Se la tua applicazione ha definito tabelle figlie ma non ha dichiarato i vincoli di chiave esterna appropriati, questo sarebbe il modo migliore per risolvere il problema.
Detto questo, la soluzione di Arnon di creare una vista dovrebbe funzionare. Dovresti rinominare la tabella, creare una vista con lo stesso nome della tabella esistente e (potenzialmente) definire un trigger INSTEAD OF sulla vista che semplicemente non aggiornerebbe mai INITIATIVEID
colonna. Ciò non dovrebbe richiedere modifiche ad altri bit dell'applicazione.
Potresti anche definire un trigger sul tavolo
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;
Qualcuno potrebbe, ovviamente, disabilitare il trigger ed emettere un aggiornamento. Ma presumo che tu non stia cercando di fermare un utente malintenzionato, solo un pezzo di codice difettoso.
Sulla base della descrizione dei sintomi che stai vedendo, tuttavia, sembrerebbe più sensato registrare la cronologia delle modifiche alle colonne in questa tabella in modo che tu possa effettivamente determinare cosa sta succedendo piuttosto che indovinare e provare a tappare i buchi uno -per uno. Quindi, ad esempio, potresti fare qualcosa del genere
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;
Quindi puoi interrogare TPM_INITIATIVES_HIST
per visualizzare tutte le modifiche apportate a una determinata riga nel tempo. Quindi puoi vedere se i valori della chiave primaria stanno cambiando o se qualcuno sta solo modificando i campi non chiave. Idealmente, potresti avere colonne aggiuntive che puoi aggiungere alla tabella della cronologia per aiutare a tenere traccia delle modifiche (ad esempio, forse c'è qualcosa da V$SESSION
potrebbe essere utile).