Oracle中的触发器:未找到任何数据

时间:2016-06-10 17:48:45

标签: oracle

请检查我的代码,我很少使用触发器和AFTER子句,非常感谢:

set serveroutput on;
create or replace trigger tvideo_2 after insert on video for each row
declare 
pragma autonomous_transaction;
v_title video.title%type; /* Declare a variable to check title that contain '18+' */
begin
select title into v_title from video where video.videoid=:new.videoid;
if v_title like '%18+%' then
update video
set age=18
where videoid=:new.videoid;
dbms_output.put_line('Video '||:new.videoid||' has been updated age to 18+');
else
dbms_output.put_line('Video '||:new.videoid||' is not 18+!');
end if;
end;
/
insert into video values('V5', '18+', 240, 19);
VIDEO properties: (videoid, title, duration, age)

1 个答案:

答案 0 :(得分:0)

使用pragma autonomous_transaction意味着触发器无法看到刚刚插入的行以及导致它被触发的行。

当您删除主键并预先插入具有相同ID的记录时,它的行将由您的触发器更新,而不是您要插入的新行 - 所以它仍然不会做你想做的事情,并且复制PK值无论如何都是不合理的。

如果您必须以after insert触发器执行此操作,那么您可以删除for each row,这可以避免您可能试图避免的变异表问题,但之后您必须查询整个表找到要更新的行:

create or replace trigger tvideo_2 after insert on video
begin
  update video
  set age = 18
  where title like '%18+%'
  and age != 18;
end;
/

或者如果您想要打印消息:

create or replace trigger tvideo_2 after insert on video
begin
  for rec in (
    select videoid, title
    from video
    where title like '%18+%'
    and age != 18
  )
  loop
    update video
    set age = 18
    where video.videoid = rec.videoid;
    dbms_output.put_line('Video '||rec.videoid||' has been updated age to 18+');
  end loop;
end;
/

但是在触发器中使用dbms_output,或者在任何存储的PL / SQL中使用for update并不是一个好主意 - 如果执行插入的客户端会话没有查看输出缓冲区而不是该消息丢失了,无论如何都不会(或没有人)看到它。

您还可以使用update .. where current ofcreate or replace trigger tvideo_2 before insert on video for each row begin if :new.title like '%18+%' then :new.age := 18; dbms_output.put_line('Video '||:new.videoid||' has been updated age to 18+'); else dbms_output.put_line('Video '||:new.videoid||' is not 18+!'); end if; end; / 的显式光标。

无论哪种方式,您都需要查询整个表格,这不是非常有效 - 每次插入新表格时都要检查所有现有行,而不是仅检查单个新行值。触发器并不适合做那么多工作 - 即使它实际上只更新了一行(或者没有!),它必须查询每个插入的所有内容。这不会很好地扩展。

还有其他方法可以避免变异表问题,但任何事情都会成为黑客攻击。执行此操作的明智方法是使用插入前行级别触发器:

dbms_output

(关于使用select tableAB.a, tableP.a from table as tableAB inner join table as tableP on tableAB.b = tableP.b where tableAB.a = '00AB' and tableP.a != '00AB' 有同样的警告),但出于某种原因似乎禁止这样做。