Oracle
 sql >> Base de données >  >> RDS >> Oracle

Quel est le moyen le plus simple de créer une colonne READONLY dans Oracle ?

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).