2010-02-25 7 views
6

que tienen un disparador AFTER INSERT OR UPDATE OR DELETE que estoy escribiendo para almacenar cada revisión registro que se produce en una determinada mesa, copiando los INSERT y UPDATE:NEW valores en una tabla de espejo, y para DELETE:OLD los valores.¿Puedo copiar: Pseudoregistros VIEJO y NUEVO en/a un procedimiento almacenado de Oracle?

Podría desordenar considerablemente mi código pasando condicionalmente el registro :NEW o :OLD a un procedimiento que luego insertaría en mi tabla de historial. Desafortunadamente, parece que no puedo encontrar la manera de pasar el registro completo :OLD o :NEW.

¿Me falta algo o no hay manera de evitar enumerar cada columna :NEW y :OLD cuando invoco mi procedimiento de inserción?

Quiero hacer lo siguiente:

DECLARE 
    PROCEDURE LOCAL_INSERT(historyRecord in ACCT.ACCOUNTS%ROWTYPE) IS 
    BEGIN 
    INSERT INTO ACCT.ACCOUNTS_HISTORY (ID, NAME, DESCRIPTION, DATE) VALUES (historyRecord.ID, historyRecord.NAME, historyRecord.DESCRIPTION, SYSDATE); 
    END; 
BEGIN 
    IF INSERTING OR UPDATING THEN 
    LOCAL_INSERT(:NEW); 
    ELSE --DELETING 
    LOCAL_INSERT(:OLD); 
    END IF; 
END; 

Pero estoy atascado hacer esto:

DECLARE 
    PROCEDURE LOCAL_INSERT(id in ACCT.ACCOUNTS.ID%TYPE, 
         name in ACCT.ACCOUNTS.NAME%TYPE, 
         description in ACCT.ACCOUNTS.DESCRIPTION%TYPE) IS 
    BEGIN 
    INSERT INTO ACCT.ACCOUNTS_HISTORY (ID, NAME, DESCRIPTION, DATE) VALUES (id, name, description, SYSDATE); 
    END; 
BEGIN 
    IF INSERTING OR UPDATING THEN 
    LOCAL_INSERT(:NEW.ID, :NEW.NAME, :NEW.DESCRIPTION); 
    ELSE --DELETING 
    LOCAL_INSERT(:OLD.ID, :OLD.NAME, :OLD.DESCRIPTION); 
    END IF; 
END; 

bien, por lo que no se ve como una gran diferencia, pero esto es sólo un ejemplo con 3 columnas en lugar de docenas.

Respuesta

3

No lo es. Tienes que hacerlo tú mismo a través de la enumeración.

Las razones por las que no puede/no funciona de forma automática incluyen:

  • la :old y :new son convenciones predeterminadas; puede nombrar las referencias :old y :new para que sean lo que quiera a través de la cláusula REFERENCING de la declaración CREATE TRIGGER.

  • tendrías que tener una declaración pública de un tipo (a través de CREATE TYPE o a través de una declaración de paquete) para poder usarlo como argumento para otro fragmento de código.

  • código de activación es código interpretado, código no compilado.

1

No creo que sea posible así. Documentation no menciona nada de eso.

Esto ciertamente costo de rendimiento, pero se puede tratar de definir su disparador AFTER INSERT y otro BEFORE UPDATE OR DELETE, y en el gatillo de hacer algo como:

SELECT * 
INTO rowtype_variable 
FROM accounts 
WHERE accounts.id = :NEW.id; -- :OLD.id for UPDATE and DELETE 

y póngase en contacto con el procedimiento que rowtype_variable.

0

Use SQL para generar el SQL;

select ' row_field.'||COLUMN_NAME||' := :new.'||COLUMN_NAME||';' from 
    ALL_TAB_COLUMNS cols 
where 
    cols.TABLE_NAME = 'yourTableName' 
order by cols.column_name. 

A continuación, copie y pegue la salida.

0

Si utiliza DESPUÉS gatillo puede utilizar rowid como parámetro para llamar a procedimiento

insert into t_hist 
select * from t where rowid = r; 

Si utiliza ANTES gatillo obtendrá ORA-04091 mutando mesa, PERO tu solución puede ser (http://www.dba-oracle.com/t_avoiding_mutating_table_error.htm):

  • No utilice desencadenantes: la mejor forma de evitar el error de la tabla de mutación es no usar activadores. Mientras que el Oracle orientado a objetos proporciona "métodos" que están asociados con las tablas, la mayoría de los desarrolladores PL/SQL inteligentes evitan los desencadenantes a menos que sea absolutamente necesario.
  • Utilice un desencadenante "después" o "en lugar de": si debe usar un desencadenador, es mejor evitar el error de tabla de mutación utilizando un desencadenante "después" para evitar los problemas de moneda asociados con una tabla de mutación. Por ejemplo, usando un disparador ": después de la actualización en xxx", la actualización original se ha completado y la tabla no estará mutando.
  • Vuelva a trabajar la sintaxis del activador: el Dr. Hall tiene algunas notas geniales sobre los errores de mutación en la tabla y ofrece otras maneras de evitar la mutación de tablas con una combinación de activadores a nivel de fila y de declaración.
  • Usar transacciones autónomas: puede evitar el error de la tabla de mutación marcando su desencadenante como una transacción autónoma, haciéndolo independiente de la tabla que llama al procedimiento.
Cuestiones relacionadas