在oracle

时间:2018-06-22 09:21:29

标签: sql oracle plsql triggers

我是学习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

我尝试搜索所有内容,但找不到任何解决方案

2 个答案:

答案 0 :(得分:3)

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           

答案 1 :(得分:0)

首先,您需要了解触发器,突变表错误和复合触发器:http://docs.oracle.com/cd/E11882_01/appdev.112/e25519/triggers.htm#LNPLS2005

您的触发器是在更新或插入之后。意味着如果在此表上运行UPDATE或INSERT语句,触发器将触发。但是您尝试在触发器内部再次更新同一表,即compl。错误的。

我认为您可以通过将其重写为before触发器而不是after触发器来解决此问题。