简体   繁体   中英

Updating the record of same table when new record is inserted or updated in oracle

I am new to learning Oracle. I have a task in which I need to update value of any previous record if new record contains its reference.

Table structure is as below :

Review_Table 
  (review_id         number pk, 
   review_name       varchar2, 
   previous_review   number  null, 
   followup_review   number  null
  )

Here previous_review and followup_review columns are objects of same table ie Review_table.

Now consider we have two records in Review_table A and B, A does not have any previous or followup review. When user creates/updates the record B and he selects record A as previous record, then we want to automatically update (via trigger) the value of A record's followup review with B's Review ID.

I have tried writing following trigger

create or replace trigger "REVIEW_T1"
  AFTER insert or update on "REVIEW_TABLE"
  for each row
begin
  update REVIEW_TABLE
    set review_follow_up_review = :new.REVIEW_ID
    where REVIEW_ID = :new.REVIEW_PREVIOUS_REVIEW;        
end;

But I am getting error as : REVIEW_TABLE is mutating, trigger/function may not see it ORA-06512

I have tried searching everything but was unable to find any solution for it

TL;DR: No trigger, no mutating. Do not use trigger to change another row in the same table.

I absolutely agree with @StevenFeuerstein's comment :

I also suggest not using a trigger at all. Instead, create a package that contains two procedures, one to insert into table, one to update. And within these procedures, implement the above logic. Then make sure that the only way developers and apps can modify the table is through this package (don't grant privs on the table, only execute on the package).

Take a look at the following example.

Prepare the schema:

create table reviews (
    id         number primary key, 
    name       varchar2 (32), 
    previous   number, 
    followup   number
    );

create or replace procedure createNextReview (name varchar2, lastId number := null) is
    lastReview reviews%rowtype;
    nextReview reviews%rowtype;
    function getLastReview (lastId number) return reviews%rowtype is
    begin
        for ret in (
            select * from reviews where id = lastId
            for update
            ) loop return ret; end loop;
        raise_application_error (-20000, 'last review does not exist');
    end;
    procedure insertReview (nextReview reviews%rowtype) is
    begin 
        insert into reviews values nextReview;
    exception when others then      
        raise_application_error (-20000, 'cannot insert next review');
    end;
    procedure setFollowUp (nextId number, lastId number) is
    begin
        update reviews set
            followup = nextId
        where id = lastId
        ;
    exception when others then      
        raise_application_error (-20000, 'cannot update last review');
    end;
begin
    if lastId is not null then
        lastReview := getLastReview (lastId);
    end if;
    nextReview.id := coalesce (lastReview.id, 0)+1;
    nextReview.name := name;
    nextReview.previous := lastId;
    insertReview (nextReview);
    if lastReview.Id is not null then
        setFollowUp (nextReview.id, lastReview.Id); 
    end if;
exception when others then
    dbms_output.put_line (
       'createNextReview: '||sqlerrm||chr(10)||dbms_utility.format_error_backtrace ()
       );
end;
/

Execute:

exec createNextReview ('first review')
exec createNextReview ('next  review', 1)

See the outcome of work done:

select * from reviews;

        ID NAME               PREVIOUS   FOLLOWUP
---------- ---------------- ---------- ----------
         1 first review                         2
         2 next  review              1           

First you need to read about triggers, mutating table error and compound triggers: http://docs.oracle.com/cd/E11882_01/appdev.112/e25519/triggers.htm#LNPLS2005

Your trigger is AFTER UPDATE OR INSERT. Means if you run UPDATE OR INSERT statements on this table, the trigger will fire. But you are trying to update the same table again inside your trigger, which is compl. wrong.

I think you can fix this by rewriting this as a before trigger, rather than an after trigger.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM