sql >> Base de Datos >  >> RDS >> Oracle

¿Cuál es la forma más fácil de hacer una columna READONLY en Oracle?

Si hay tablas secundarias con datos que hacen referencia al INITIATIVEID columna, Oracle debería dificultar automáticamente el cambio del valor de la clave principal al evitar que cree filas huérfanas al cambiar la clave principal del padre. Entonces, por ejemplo, si hay una tabla secundaria que tiene una restricción de clave externa para TPM_INITIATIVES y hay una fila en esta tabla secundaria con un INITIATIVEID de 17, no podrá cambiar el INITIATIVEID de la fila en el TPM_INITIAITVES tabla cuyo valor actual es 17. Si no hay ninguna fila en ninguna tabla secundaria que haga referencia a la fila en particular en TPM_INITIATIVES table, podría cambiar el valor pero, presumiblemente, si no hay relaciones, cambiar el valor de la clave principal no es importante ya que, por definición, no puede causar un problema de integridad de datos. Por supuesto, podría tener un código que inserte una nueva fila en TPM_INITIATIVES con un nuevo INITIATIVEID , cambie todas las filas de la tabla secundaria que hacen referencia a la fila anterior para que hagan referencia a la fila nueva y, a continuación, modifique la fila anterior. Pero esto no quedará atrapado por ninguna de las soluciones propuestas.

Si su aplicación ha definido tablas secundarias pero no ha declarado las restricciones de clave externa apropiadas, esa sería la mejor manera de resolver el problema.

Dicho esto, la solución de Arnon de crear una vista debería funcionar. Cambiaría el nombre de la tabla, crearía una vista con el mismo nombre que la tabla existente y (potencialmente) definiría un disparador INSTEAD OF en la vista que simplemente nunca actualizaría el INITIATIVEID columna. Eso no debería requerir cambios en otras partes de la aplicación.

También puede definir un activador en la tabla

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;

Alguien podría, por supuesto, deshabilitar el disparador y emitir una actualización. Pero asumo que no estás tratando de detener a un atacante, solo una pieza de código con errores.

Sin embargo, en función de la descripción de los síntomas que está viendo, parecería tener más sentido registrar el historial de cambios en las columnas de esta tabla para que pueda determinar realmente qué está sucediendo en lugar de adivinar e intentar tapar los agujeros. -por uno. Entonces, por ejemplo, podrías hacer algo como esto

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;

Luego puede consultar TPM_INITIATIVES_HIST para ver todos los cambios que se han realizado en una fila en particular a lo largo del tiempo. Entonces puede ver si los valores de la clave principal están cambiando o si alguien solo está cambiando los campos que no son clave. Idealmente, puede tener columnas adicionales que puede agregar a la tabla de historial para ayudar a rastrear los cambios (es decir, tal vez haya algo de V$SESSION eso podría ser útil).