开发者

Can I copy :OLD and :NEW pseudo-records in/to an Oracle stored procedure?

I have an AFTER INSERT OR UPDATE OR DELETE trigger that I'm writing to store every record revision that occurs in a c开发者_运维问答ertain table, by copying the INSERT and UPDATE :NEW values into a mirror table, and for DELETE the :OLD values.

I could un-clutter my code considerably by conditionally passing either the :NEW or :OLD record into a procedure which would then do the insert into my history table. Unfortunately I cannot seem to find a way to pass the entire :OLD or :NEW record.

Am I missing something or is there no way to avoid enumerating every :NEW and :OLD column as I invoke my insert procedure?

I want to do the following:

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;

But I'm stuck doing this:

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;

Okay, so it doesn't look like a big difference, but this is just an example with 3 columns rather than dozens.


It isn't. You have to do it yourself through enumeration.

The reasons it can't/doesn't work automatically include:

  • the :old and :new are default conventions; you can name the :old and :new references to be whatever you want through the REFERENCING clause of the CREATE TRIGGER statement.

  • you'd have to have a public declaration of a type (through CREATE TYPE or through a package declaration) to be able to use it as an argument to another piece of code.

  • trigger code is interpreted code, not compiled code.


I don't think it's possible like that. Documentation doesn't mention anything like that.

This would certainly cost performance, but you could try to define your trigger AFTER INSERT and another one BEFORE UPDATE OR DELETE, and in the trigger do something like:

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

and then call your procedure with that rowtype_variable.


Use SQL to generate the SQL;

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

Then copy and paste output.


If you use AFTER trigger you can use rowid as parameter to call procedure

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

If you use BEFORE trigger you will get ORA-04091 mutating table, BUT you solution can be (http://www.dba-oracle.com/t_avoiding_mutating_table_error.htm):

  • Don't use triggers - The best way to avoid the mutating table error is not to use triggers. While the object-oriented Oracle provides "methods" that are associated with tables, most savvy PL/SQL developers avoid triggers unless absolutely necessary.
  • Use an "after" or "instead of" trigger - If you must use a trigger, it's best to avoid the mutating table error by using an "after" trigger, to avoid the currency issues associated with a mutating table. For example, using a trigger ":after update on xxx", the original update has completed and the table will not be mutating.
  • Re-work the trigger syntax - Dr. Hall has some great notes on mutating table errors, and offers other ways to avoid mutating tables with a combination of row-level and statement-level triggers.
  • Use autonomous transactions - You can avoid the mutating table error by marking your trigger as an autonomous transaction, making it independent from the table that calls the procedure.
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜