sql >> Databasteknik >  >> RDS >> Oracle

Vad är det enklaste sättet att göra en kolumn LÄSENDAST i Oracle?

Om det finns underordnade tabeller fyllda med data som refererar till INITIATIVEID kolumnen bör Oracle automatiskt göra det svårt att ändra primärnyckelns värde genom att förhindra dig från att skapa föräldralösa rader genom att ändra förälderns primärnyckel. Så, till exempel, om det finns en underordnad tabell som har en främmande nyckel-begränsning till TPM_INITIATIVES och det finns en rad i denna underordnade tabell med ett INITIATIVEID av 17 kommer du inte att kunna ändra INITIATIVEID av raden i TPM_INITIAITVES tabell vars nuvarande värde är 17. Om det inte finns någon rad i någon underordnad tabell som refererar till den specifika raden i TPM_INITIATIVES tabell kan du ändra värdet, men förmodligen, om det inte finns några relationer, är det oviktigt att ändra det primära nyckelvärdet eftersom det per definition inte kan orsaka ett dataintegritetsproblem. Naturligtvis kan du ha kod som infogar en ny rad i TPM_INITIATIVES med ett nytt INITIATIVEID , ändra alla rader i den underordnade tabellen som hänvisar till den gamla raden för att hänvisa till den nya raden, ändra sedan den gamla raden. Men detta kommer inte att fångas av någon av de föreslagna lösningarna.

Om ditt program har definierat underordnade tabeller men inte deklarerat lämpliga begränsningar för främmande nyckel, skulle det vara det bästa sättet att lösa problemet.

Med det sagt borde Arnons lösning att skapa en vy fungera. Du skulle byta namn på tabellen, skapa en vy med samma namn som den befintliga tabellen och (potentiellt) definiera en INSTEAD OF trigger på vyn som helt enkelt aldrig skulle uppdatera INITIATIVEID kolumn. Det borde inte kräva ändringar i andra delar av programmet.

Du kan också definiera en trigger på bordet

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;

Någon kan naturligtvis inaktivera triggern och utfärda en uppdatering. Men jag antar att du inte försöker stoppa en angripare, bara en buggig kod.

Baserat på beskrivningen av vilka symtom du ser, verkar det dock vara mer meningsfullt att logga historiken för ändringar av kolumner i den här tabellen så att du faktiskt kan avgöra vad som pågår istället för att gissa och försöka täppa till hål ett -av en. Så du kan till exempel göra något sånt här

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;

Sedan kan du fråga TPM_INITIATIVES_HIST för att se alla ändringar som har gjorts på en viss rad över tiden. Så du kan se om de primära nyckelvärdena ändras eller om någon bara ändrar icke-nyckelfälten. Helst kan du ha ytterligare kolumner som du kan lägga till i historiktabellen för att hjälpa till att spåra ändringarna (dvs. det kanske finns något från V$SESSION som kan vara användbart).



  1. Hur ställer man in korrekta attributnamn till ett aggregerat json-resultat med GROUP BY-sats?

  2. Hur man använder INNER JOIN i SQL

  3. LÄGRE LIKE vs iLIKE

  4. Aggregera booleska värden till sant om någon av källkolumnerna är sann