2009-09-14 9 views
9

en Oracle puedo especificar las columnas, lo que debería inducir un disparo de un disparador:Oracle: excluyendo las actualizaciones de una columna para disparar un gatillo

create or replace trigger my_trigger 
before update of col1, col2, col3 on my_table for each row 
begin 
    // the trigger code will be executed only if col1 or col2 or col3 was updated 
end; 

Ahora quiero hacer lo siguiente: I don' t desea que se dispare el disparador, cuando se actualizó una sola columna. ¿Cómo es esto posible?

Pude enumerar todas las columnas excepto la que no debe inducir un disparo del gatillo. Esto es bastante engorroso para tablas con muchas columnas.

Otra forma sería la de utilizar la función de actualización de esta manera:

if not updating('COL3') then ... 

Pero si cambiaba col1 y COL3 a la vez, la declaración se evalúa como falsa. Eso no es lo que quiero, ya que quiero restringir la ejecución cuando se actualizó una sola columna (COL3).

+0

Es menos engorroso enumerar todas las columnas con el diccionario de datos. 'SELECCIONAR column_name FROM user_tab_columns WHERE table_name = 'MY_TABLE' AND column_name! = 'COL3';' –

+0

Eso es cierto, pero alguien más tendrá que mantener el activador. Si agregamos una nueva columna o la cambiamos de nombre ... ya puedo escucharlo exclamar en voz alta. Me gustaría encontrar una manera confiable con menos dolor para él y especialmente para mí. ;-) –

Respuesta

11

se podría hacer algo como esto:

create or replace trigger my_trigger 
before update on my_table 
for each row 
declare 
    n_cols integer := 0; 
begin 
    for r in (select column_name from all_tab_columns 
      where table_name = 'MY_TABLE' 
      and owner = 'MY_SCHEMA') 
    loop 
     if updating(r.column_name) then 
     n_cols := n_cols + 1; 
     exit when n_cols > 1; 
     end if; 
    end loop; 
    if n_cols > 1 then 
     do_something; 
    end if; 
end; 

Probablemente no muy eficiente, aunque!

0

No creo que haya una manera de evitar tener que enumerar todas las demás columnas de la tabla, ya sea en el cuerpo del disparador o en la cláusula before update of ....

Sin embargo, es posible que pueda escribir un desencadenador alternativo en la tabla para regenerar el activador de actualización automáticamente si se agregan o quitan columnas. Es un poco más de trabajo, pero luego el mantenimiento debe ser automático.

3

Probablemente no sea la respuesta que desea escuchar, pero creo que exagera demasiado la carga del mantenimiento. No es normal que la estructura de una tabla cambie muy seguido después de que entre en producción. Si tiene una tabla que está sujeta a cambios frecuentes de número de columna o nombre, entonces le sugiero que tenga un problema arquitectónico más grande.

Así que simplemente escriba todos los nombres de las columnas ahora y espere a ver si el mantenimiento se convierte en un problema. Ciertamente, no vale la pena codificar una implementación complicada en un desencadenante, un impuesto que pagará en cada actualización, para evitar ocasionalmente cambios en el script DDL.

5

Tuve el mismo problema ayer. Quería codificar un disparador que disparara en todos los campos excepto en uno, la tabla tenía 103 columnas.

Primero codificado:

if (:OLD.col1<>:NEW.col1 or :OLD.col2<>:NEW.col2 or :OLD.col3<>:NEW.col3 ....) 

Pero tuve algunos problemas con valores nulos, por lo que añade:

if (NVL(:OLD.col1,0)<>NVL(:NEW.col1,0) or NVL(:OLD.col2,0)<>NVL(:NEW.col2,0) ....) 

Pero luego tuve algunos problemas con columnas DATE, se convirtió en un desastre. .

Creo que la mejor solución es hacer una lista de todas las columnas que desea verificar en el "OF":

AFTER INSERT OR UPDATE of cOL1, col2, col3 ... colN ON table1 

No era "elegante" pero ...funcionó perfecto

+0

este es en realidad el más elegante de todos .. –

Cuestiones relacionadas