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).