Oracle
 sql >> Datenbank >  >> RDS >> Oracle

Was ist der einfachste Weg, um eine Spalte in Oracle schreibgeschützt zu machen?

Wenn es untergeordnete Tabellen gibt, die mit Daten gefüllt sind, die auf INITIATIVEID verweisen -Spalte sollte Oracle es automatisch erschweren, den Primärschlüsselwert zu ändern, indem verhindert wird, dass Sie verwaiste Zeilen erstellen, indem Sie den Primärschlüssel des übergeordneten Elements ändern. Wenn also beispielsweise eine untergeordnete Tabelle eine Fremdschlüsseleinschränkung für TPM_INITIATIVES hat und es gibt eine Zeile in dieser untergeordneten Tabelle mit einer INITIATIVEID von 17 können Sie die INITIATIVEID nicht ändern der Zeile in TPM_INITIAITVES Tabelle, deren aktueller Wert 17 ist. Wenn es keine Zeile in einer untergeordneten Tabelle gibt, die auf die bestimmte Zeile in TPM_INITIATIVES verweist Tabelle, Sie könnten den Wert ändern, aber wenn es keine Beziehungen gibt, ist es vermutlich unwichtig, den Primärschlüsselwert zu ändern, da es per Definition kein Datenintegritätsproblem verursachen kann. Natürlich könnten Sie Code haben, der eine neue Zeile in TPM_INITIATIVES einfügt mit einer neuen INITIATIVEID , ändern Sie alle Zeilen in der untergeordneten Tabelle, die auf die alte Zeile verweisen, um auf die neue Zeile zu verweisen, und ändern Sie dann die alte Zeile. Dies wird jedoch von keiner der vorgeschlagenen Lösungen abgefangen.

Wenn Ihre Anwendung untergeordnete Tabellen definiert, aber nicht die entsprechenden Fremdschlüsseleinschränkungen deklariert hat, wäre dies der beste Weg, um das Problem zu lösen.

Davon abgesehen sollte Arnons Lösung zum Erstellen einer Ansicht funktionieren. Sie würden die Tabelle umbenennen, eine Ansicht mit demselben Namen wie die vorhandene Tabelle erstellen und (möglicherweise) einen INSTEAD OF-Trigger für die Ansicht definieren, der die INITIATIVEID einfach nie aktualisieren würde Säule. Das sollte keine Änderungen an anderen Teilen der Anwendung erfordern.

Sie könnten auch einen Trigger für die Tabelle definieren

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;

Jemand könnte natürlich den Trigger deaktivieren und ein Update herausgeben. Aber ich gehe davon aus, dass Sie nicht versuchen, einen Angreifer aufzuhalten, sondern nur ein fehlerhaftes Stück Code.

Basierend auf der Beschreibung der Symptome, die Sie sehen, scheint es jedoch sinnvoller zu sein, den Verlauf der Änderungen an Spalten in dieser Tabelle zu protokollieren, damit Sie tatsächlich feststellen können, was vor sich geht, anstatt zu raten und zu versuchen, Löcher zu stopfen -einzeln. Sie könnten also zum Beispiel so etwas tun

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;

Dann können Sie TPM_INITIATIVES_HIST abfragen um alle Änderungen anzuzeigen, die im Laufe der Zeit an einer bestimmten Zeile vorgenommen wurden. So können Sie sehen, ob sich die Primärschlüsselwerte ändern oder ob jemand nur die Nicht-Schlüsselfelder ändert. Idealerweise haben Sie zusätzliche Spalten, die Sie der Verlaufstabelle hinzufügen können, um die Verfolgung der Änderungen zu erleichtern (d. h. vielleicht gibt es etwas von V$SESSION das könnte nützlich sein).