Oracle
 sql >> Base de Dados >  >> RDS >> Oracle

Qual é a maneira mais fácil de fazer uma coluna READONLY no Oracle?


Se houver tabelas filhas preenchidas com dados que fazem referência ao INITIATIVEID coluna, o Oracle deve dificultar automaticamente a alteração do valor da chave primária, impedindo que você crie linhas órfãs alterando a chave primária do pai. Assim, por exemplo, se houver uma tabela filha que tenha uma restrição de chave estrangeira para TPM_INITIATIVES e há uma linha nesta tabela filha com um INITIATIVEID de 17, você não poderá alterar o INITIATIVEID da linha no TPM_INITIAITVES tabela cujo valor atual é 17. Se não houver linha em nenhuma tabela filha que se refira à linha específica no TPM_INITIATIVES table, você pode alterar o valor, mas, presumivelmente, se não houver relacionamentos, alterar o valor da chave primária não é importante, pois não pode, por definição, causar um problema de integridade de dados. Claro, você pode ter um código que insere uma nova linha em TPM_INITIATIVES com um novo INITIATIVEID , altere todas as linhas na tabela filha que se referem à linha antiga para se referir à nova linha e modifique a linha antiga. Mas isso não será aprisionado por nenhuma das soluções propostas.

Se seu aplicativo definiu tabelas filhas, mas não declarou as restrições de chave estrangeira apropriadas, essa seria a melhor maneira de resolver o problema.

Dito isto, a solução de Arnon de criar uma visão deve funcionar. Você renomearia a tabela, criaria uma visualização com o mesmo nome da tabela existente e (potencialmente) definiria um gatilho INSTEAD OF na visualização que simplesmente nunca atualizaria o INITIATIVEID coluna. Isso não deve exigir alterações em outros bits do aplicativo.

Você também pode definir um gatilho na tabela
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;

Alguém poderia, é claro, desabilitar o gatilho e emitir uma atualização. Mas estou assumindo que você não está tentando parar um invasor, apenas um pedaço de código com erros.

Com base na descrição de quais sintomas você está vendo, no entanto, parece fazer mais sentido registrar o histórico de alterações nas colunas desta tabela para que você possa realmente determinar o que está acontecendo, em vez de adivinhar e tentar tapar os buracos um -por um. Então, por exemplo, você poderia fazer algo assim
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;

Então você pode consultar TPM_INITIATIVES_HIST para ver todas as alterações que foram feitas em uma linha específica ao longo do tempo. Assim, você pode ver se os valores da chave primária estão mudando ou se alguém está apenas alterando os campos não-chave. Idealmente, você pode ter colunas adicionais que você pode adicionar à tabela de histórico para ajudar a rastrear as alterações (ou seja, talvez haja algo de V$SESSION que pode ser útil).