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

Hvad er den nemmeste måde at lave en kolonne KUN på i Oracle?

Hvis der er underordnede tabeller udfyldt med data, der refererer til INITIATIVEID kolonne, skulle Oracle automatisk gøre det vanskeligt at ændre den primære nøgleværdi ved at forhindre dig i at oprette forældreløse rækker ved at ændre forælderens primære nøgle. Så hvis der for eksempel er en undertabel, der har en fremmednøgle-begrænsning til TPM_INITIATIVES og der er en række i denne underordnede tabel med et INITIATIVEID af 17, vil du ikke være i stand til at ændre INITIATIVEID af rækken i TPM_INITIAITVES tabel, hvis aktuelle værdi er 17. Hvis der ikke er nogen række i nogen underordnet tabel, der refererer til den bestemte række i TPM_INITIATIVES tabel, kan du ændre værdien, men hvis der ikke er nogen relationer, er ændring af den primære nøgleværdi uvigtig, da det ikke pr. definition kan forårsage et dataintegritetsproblem. Selvfølgelig kan du have kode, der indsætter en ny række i TPM_INITIATIVES med et nyt INITIATIVEID , ændre alle rækkerne i den underordnede tabel, der refererer til den gamle række, til at henvise til den nye række, og modificer derefter den gamle række. Men dette vil ikke blive fanget af nogen af ​​de foreslåede løsninger.

Hvis din applikation har defineret underordnede tabeller, men ikke erklæret de passende fremmednøglebegrænsninger, ville det være den bedste måde at løse problemet på.

Når det er sagt, så burde Arnons løsning med at skabe en udsigt virke. Du ville omdøbe tabellen, oprette en visning med samme navn som den eksisterende tabel og (potentielt) definere en ISTEDEN FOR trigger på visningen, der simpelthen aldrig ville opdatere INITIATIVEID kolonne. Det burde ikke kræve ændringer af andre dele af applikationen.

Du kan også definere 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;

Nogen kunne selvfølgelig deaktivere triggeren og udstede en opdatering. Men jeg går ud fra, at du ikke forsøger at stoppe en angriber, bare et buggy stykke kode.

Baseret på beskrivelsen af, hvilke symptomer du ser, ser det dog ud til at være mere fornuftigt at logge historikken for ændringer af kolonner i denne tabel, så du faktisk kan bestemme, hvad der foregår i stedet for at gætte og prøve at lukke huller en. - efter en. Så du kunne for eksempel gøre sådan noget

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;

Derefter kan du forespørge TPM_INITIATIVES_HIST for at se alle de ændringer, der var blevet foretaget i en bestemt række over tid. Så du kan se, om de primære nøgleværdier ændrer sig, eller om nogen bare ændrer de ikke-nøglefelter. Ideelt set kan du have yderligere kolonner, som du kan tilføje til historiktabellen for at hjælpe med at spore ændringerne (dvs. måske er der noget fra V$SESSION det kan være nyttigt).



  1. indsæt sætning i postgres for datatype tidsstempel uden tidszone NOT NULL,

  2. Heroku Error:ActionView::Template::Error (udefineret metode `captcha' for #<Meddelelse:0x007fc9df016930>)

  3. Sådan fungerer ADDDATE() i MariaDB

  4. Sådan finder du navnet på en begrænsning i MySQL