Oracle
 sql >> Database >  >> RDS >> Oracle

Qual è il modo più semplice per creare una colonna READONLY in Oracle?

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