简体   繁体   English

在oracle中插入或更新新记录时更新同一表的记录

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

I am new to learning Oracle. 我是新来学习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. 在这里,previous_review和followup_review列是同一表(即Review_table)的对象。

Now consider we have two records in Review_table A and B, A does not have any previous or followup review. 现在考虑我们在Review_table A和B中有两个记录,A没有任何先前或后续的审查。 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. 当用户创建/更新记录B并选择记录A作为先前的记录时,我们要使用B的评论ID自动(通过触发)更新A记录的后续评论的值。

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 但是我收到错误消息,因为:REVIEW_TABLE正在变异,触发器/函数可能看不到它ORA-06512

I have tried searching everything but was unable to find any solution for it 我尝试搜索所有内容,但找不到任何解决方案

TL;DR: No trigger, no mutating. TL; DR:无触发器,无变异。 Do not use trigger to change another row in the same table. 不要使用触发器更改同一表中的另一行。

I absolutely agree with @StevenFeuerstein's comment : 我绝对同意@StevenFeuerstein的评论

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). 然后确保开发人员和应用程序可以修改表的唯一方法是通过此程序包(不要在表上授予privs,只能在程序包上执行)。

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 首先,您需要阅读有关触发器,表错误突变和复合触发器的信息: http : //docs.oracle.com/cd/E11882_01/appdev.112/e25519/triggers.htm#LNPLS2005

Your trigger is AFTER UPDATE OR INSERT. 您的触发器是AFTER UPDATE或INSERT。 Means if you run UPDATE OR INSERT statements on this table, the trigger will fire. 意味着如果在此表上运行UPDATE或INSERT语句,触发器将触发。 But you are trying to update the same table again inside your trigger, which is compl. 但是您尝试在触发器内部再次更新同一表,即compl。 wrong. 错误。

I think you can fix this by rewriting this as a before trigger, rather than an after trigger. 我认为您可以通过将其重写为之前触发器而不是之后触发器来解决此问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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