我是学习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
我尝试搜索所有内容,但找不到任何解决方案
答案 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触发器来解决此问题。