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

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在oracle中插入或更新新记录时更新同一表的记录相关的知识,希望对你有一定的参考价值。

我是学习Oracle的新手。我有一个任务,如果新记录包含其引用,我需要更新任何先前记录的值。

表结构如下:

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

这里的previous_review和followup_review列是同一个表的对象,即Review_table。

现在考虑我们在Review_table A和B中有两条记录,A没有任何先前或后续审查。当用户创建/更新记录B并且他选择记录A作为前一记录时,我们希望使用B的评论ID自动更新(通过触发)A记录的后续评论的值。

我试过写下面的触发器

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;

但我收到错误:REVIEW_TABLE正在变异,触发/功能可能看不到它ORA-06512

我试过搜索一切,但无法找到任何解决方案

答案

TL; DR:没有触发器,没有变异。不要使用触发器来更改同一个表中的另一行。

我绝对同意@StevenFeuerstein's comment

我还建议不要使用触发器。相反,创建一个包含两个过程的包,一个用于插入表,另一个用于更新。在这些程序中,实现上述逻辑。然后确保开发人员和应用程序可以修改表的唯一方法是通过此包(不要在表上授予privs,只在包上执行)。

看一下下面的例子。

准备架构:

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;
/

执行:

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

看看完成的工作成果:

select * from reviews;

        ID NAME               PREVIOUS   FOLLOWUP
---------- ---------------- ---------- ----------
         1 first review                         2
         2 next  review              1           
另一答案

首先,您需要阅读有关触发器,变异表错误和复合触发器的信息:http://docs.oracle.com/cd/E11882_01/appdev.112/e25519/triggers.htm#LNPLS2005

您的触发器是更新或插入后。表示如果在此表上运行UPDATE OR INSERT语句,则触发器将触发。但是你试图在你的触发器内再次更新同一个表,这是compl。错误。

我认为你可以通过将其重写为前触发器而不是后触发器来解决这个问题。

以上是关于在oracle中插入或更新新记录时更新同一表的记录的主要内容,如果未能解决你的问题,请参考以下文章

如何在mysql 5中记录特定表的插入/更新查询

Oracle:Sql根据同一表另一行的值更新同一表的行

更新记录(如果存在);否则在 Oracle 中插入

如果 mysql 数据库中的表中不存在,则更新或插入多条记录

Oracle整合Mybatis实现list数据插入时,存在就更新,不存在就插入以及随机抽取一条记录

oracle,FORM,删除数据时,只能按插入的顺序删除,才不会报错。(FRM 40654 记录已被其他使用者更新 )