sql >> Database >  >> RDS >> Oracle

Wat is de gemakkelijkste manier om een ​​kolom READONLY te maken in Oracle?

Als er onderliggende tabellen zijn gevuld met gegevens die verwijzen naar de INITIATIVEID kolom, zou Oracle het automatisch moeilijk moeten maken om de waarde van de primaire sleutel te wijzigen door te voorkomen dat u weesrijen maakt door de primaire sleutel van de bovenliggende sleutel te wijzigen. Dus als er bijvoorbeeld een onderliggende tabel is met een externe sleutelbeperking voor TPM_INITIATIVES en er is een rij in deze onderliggende tabel met een INITIATIVEID van 17, kunt u de INITIATIVEID . niet wijzigen van de rij in de TPM_INITIAITVES tabel waarvan de huidige waarde 17 is. Als er geen rij is in een onderliggende tabel die verwijst naar de specifieke rij in de TPM_INITIATIVES tabel, kunt u de waarde wijzigen, maar vermoedelijk, als er geen relaties zijn, is het wijzigen van de primaire sleutelwaarde onbelangrijk, omdat dit per definitie geen gegevensintegriteitsprobleem kan veroorzaken. U kunt natuurlijk code hebben die een nieuwe rij invoegt in TPM_INITIATIVES met een nieuwe INITIATIVEID , verander alle rijen in de onderliggende tabel die naar de oude rij verwijzen om naar de nieuwe rij te verwijzen en wijzig vervolgens de oude rij. Maar dit zal niet worden gevangen door een van de voorgestelde oplossingen.

Als uw toepassing onderliggende tabellen heeft gedefinieerd, maar niet de juiste externe-sleutelbeperkingen heeft aangegeven, is dat de beste manier om het probleem op te lossen.

Dat gezegd hebbende, zou Arnons oplossing voor het creëren van een weergave moeten werken. U zou de tabel een andere naam geven, een weergave maken met dezelfde naam als de bestaande tabel en (mogelijk) een INSTEAD OF-trigger definiëren voor de weergave die simpelweg nooit de INITIATIVEID zou bijwerken kolom. Dat zou geen wijzigingen in andere delen van de applicatie moeten vereisen.

Je zou ook een trigger op de tafel kunnen definiëren

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;

Iemand zou natuurlijk de trigger kunnen uitschakelen en een update kunnen uitgeven. Maar ik neem aan dat je niet probeert een aanvaller te stoppen, maar alleen een stukje code met fouten.

Op basis van de beschrijving van de symptomen die u ziet, lijkt het echter logischer om de geschiedenis van wijzigingen in kolommen in deze tabel te loggen, zodat u daadwerkelijk kunt bepalen wat er aan de hand is in plaats van te raden en gaten te dichten. -bij een. Je zou bijvoorbeeld zoiets als dit kunnen doen

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;

Vervolgens kunt u TPM_INITIATIVES_HIST . opvragen om alle wijzigingen te zien die in de loop van de tijd in een bepaalde rij zijn aangebracht. U kunt dus zien of de primaire sleutelwaarden veranderen of dat iemand alleen de niet-sleutelvelden wijzigt. In het ideale geval heeft u misschien extra kolommen die u aan de geschiedenistabel kunt toevoegen om de wijzigingen bij te houden (d.w.z. misschien is er iets van V$SESSION dat kan handig zijn).



  1. Hoe kan ik zoeken naar een zin zoals O'% in MySql?

  2. Hoe gebruikersprofielen te maken met PHP en MySQL

  3. MySQL min en max van elke kolom

  4. Hoe NULL-waarden in datetime-velden in MySQL op te slaan?