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

ORA-04091:la tabla [blah] está mutando, es posible que el activador o la función no lo vean

Creo que no estoy de acuerdo con su descripción de lo que intenta hacer el gatillo. Me parece que está destinado a hacer cumplir esta regla comercial:para un valor dado de t1_appnt_event, solo una fila puede tener un valor no NULL oft1_prnt_t1_pk a la vez. (No importa si tienen el mismo valor en la segunda columna o no).

Curiosamente, está definido para UPDATE OF t1_appnt_event pero no para la otra columna, por lo que creo que alguien podría infringir la regla actualizando la segunda columna, a menos que haya un disparador separado para esa columna.

Puede haber una manera de crear un índice basado en funciones que aplique esta regla para que pueda deshacerse del disparador por completo. Se me ocurrió una forma, pero requiere algunas suposiciones:

  • La tabla tiene una clave principal numérica
  • La clave principal y t1_prnt_t1_pk son siempre números positivos

Si estas suposiciones son ciertas, podría crear una función como esta:

dev> create or replace function f( a number, b number ) return number deterministic as
  2  begin
  3    if a is null then return 0-b; else return a; end if;
  4  end;

y un índice como este:

CREATE UNIQUE INDEX my_index ON my_table
  ( t1_appnt_event, f( t1_prnt_t1_pk, primary_key_column) );

Entonces, las filas donde la columna PMNT es NULL aparecerán en el índice con el inverso de la clave principal como segundo valor, por lo que nunca entrarán en conflicto entre sí. Las filas donde no es NULL usarían el valor real (positivo) de la columna. La única forma en que podría obtener una violación de restricción sería si dos filas tuvieran los mismos valores no NULL en ambas columnas.

Quizás esto sea demasiado "inteligente", pero podría ayudarlo a solucionar su problema.

Actualización de Paul Tomblin:Elegí la actualización de la idea original que igor puso en los comentarios:

 CREATE UNIQUE INDEX cappec_ccip_uniq_idx 
 ON tbl1 (t1_appnt_event, 
    CASE WHEN t1_prnt_t1_pk IS NOT NULL THEN 1 ELSE t1_pk END);