S'il existe des tables enfants remplies de données faisant référence à INITIATIVEID
colonne, Oracle devrait automatiquement rendre difficile la modification de la valeur de la clé primaire en vous empêchant de créer des lignes orphelines en modifiant la clé primaire du parent. Ainsi, par exemple, s'il existe une table enfant qui a une contrainte de clé étrangère pour TPM_INITIATIVES
et il y a une ligne dans cette table enfant avec un INITIATIVEID
de 17, vous ne pourrez pas modifier le INITIATIVEID
de la ligne dans le TPM_INITIAITVES
table dont la valeur actuelle est 17. S'il n'y a aucune ligne dans une table enfant qui fait référence à la ligne particulière dans le TPM_INITIATIVES
table, vous pouvez modifier la valeur mais, vraisemblablement, s'il n'y a pas de relations, la modification de la valeur de la clé primaire n'est pas importante car elle ne peut pas, par définition, causer un problème d'intégrité des données. Bien sûr, vous pourriez avoir du code qui insère une nouvelle ligne dans TPM_INITIATIVES
avec un nouveau INITIATIVEID
, modifiez toutes les lignes de la table enfant qui font référence à l'ancienne ligne pour faire référence à la nouvelle ligne, puis modifiez l'ancienne ligne. Mais cela ne sera piégé par aucune des solutions proposées.
Si votre application a défini des tables enfants mais n'a pas déclaré les contraintes de clé étrangère appropriées, ce serait la meilleure façon de résoudre le problème.
Cela étant dit, la solution d'Arnon consistant à créer une vue devrait fonctionner. Vous renommeriez la table, créeriez une vue avec le même nom que la table existante et (potentiellement) définiriez un déclencheur INSTEAD OF sur la vue qui ne mettrait simplement jamais à jour le INITIATIVEID
colonne. Cela ne devrait pas nécessiter de modifications d'autres parties de l'application.
Vous pouvez également définir un déclencheur sur la table
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;
Quelqu'un pourrait, bien sûr, désactiver le déclencheur et publier une mise à jour. Mais je suppose que vous n'essayez pas d'arrêter un attaquant, juste un morceau de code bogué.
Sur la base de la description des symptômes que vous voyez, cependant, il semblerait plus logique de consigner l'historique des modifications apportées aux colonnes de ce tableau afin que vous puissiez réellement déterminer ce qui se passe plutôt que de deviner et d'essayer de boucher les trous un -par un. Ainsi, par exemple, vous pourriez faire quelque chose comme ça
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;
Ensuite, vous pouvez interroger TPM_INITIATIVES_HIST
pour voir toutes les modifications apportées à une ligne particulière au fil du temps. Ainsi, vous pouvez voir si les valeurs de la clé primaire changent ou si quelqu'un modifie simplement les champs non clés. Idéalement, vous pouvez avoir des colonnes supplémentaires que vous pouvez ajouter à la table d'historique pour faciliter le suivi des modifications (c'est-à-dire qu'il y a peut-être quelque chose de V$SESSION
cela pourrait être utile).