PLS-00103,在触发器中

时间:2012-05-24 12:29:13

标签: sql oracle triggers

create or replace TRIGGER log_worlds BEFORE UPDATE OR INSERT ON worlds
DECLARE
ac VARCHAR2(50);
tab VARCHAR2(50);
world VARCHAR2(50);
BEGIN
IF UPDATING THEN
ac:='Aktualizacja';
END IF;
IF INSERTING THEN
ac:='Nowe';
END IF;
tab:='WORLDS';
world:='world_';
world:=world||cast(NEW_WORLD.NEXTVAL as VARCHAR2(10));
INSERT INTO log(ACTION_DATE,ACTION,TAB_NAME,ADDED_WORLD) VALUES(SYSDATE,ac,tab,world);
INSERT INTO worlds(WORLD_NAME) VALUES(world);
END;

有人可以帮我这个,错误信息是关于第14行的吗?当我的APEX应用程序针对表发出DML时,此触发器应该向日志表添加新值并更改worlds表的主键值。

3 个答案:

答案 0 :(得分:1)

您收到的错误表明您的代码中存在一些语法错误,我无法立即找到。但是我希望另一个错误,因为Oracle不会允许你在触发器打开的同一个表的触发器内执行DML语句(选择,插入,更新,删除)。您的触发器位于表格世界中,因此不允许您在触发器内的表格世界中插入记录。

答案 1 :(得分:1)

立即语法错误是假设NEW_WORLD是您创建的序列,您需要执行类似

的操作
SELECT world ||
         cast( new_world.nextval as varchar2(10) )
  INTO world
  FROM dual;

而不是直接引用CAST中的序列。

我很清楚你的触发器应该做什么。它至少会产生一个无限循环。 INSERT上的每个WORLDS都会导致触发器触发,这会在INSERT上生成WORLDS,导致触发器触发,等等。超过最大递归深度时出错。也许您打算将其作为行级触发器而不是更改:new.world_name值的语句级触发器?如果是这种情况,你可能想要像

这样的东西
create or replace TRIGGER log_worlds 
  BEFORE UPDATE OR INSERT ON worlds
  FOR EACH ROW
DECLARE
  ac VARCHAR2(50);
  tab VARCHAR2(50);
  world VARCHAR2(50);
BEGIN
  IF UPDATING THEN
    ac:='Aktualizacja';
  END IF;
  IF INSERTING THEN
    ac:='Nowe';
  END IF;
  tab:='WORLDS';
  world:='world_';
  select world || cast(new_world.nextval as varchar2(10)
    into world
    from dual;
  INSERT INTO log(ACTION_DATE,ACTION,TAB_NAME,ADDED_WORLD) 
    VALUES(SYSDATE,ac,tab,world);
  :new.world_name := world;
END;

这假定world_name实际上不是主键。如果world_name是主键,那么在更新行时修改主键值是没有意义的 - 如果您正在执行INSERT,则只希望分配主键。

答案 2 :(得分:1)

我认为这就是这一行:

world:=world||cast(NEW_WORLD.NEXTVAL as VARCHAR2(10));

如果将其替换为:

world := world||to_char(NEW_WORLD.NEXTVAL);

它应该有用。

顺便说一句:直接在作业中使用nextval调用对11.x之前的版本不起作用(此处不确定x的值)。

在10.x中,您需要声明一个变量,然后使用:

SELECT to_char(new_world.nextval)
   into world_num;
world := world || world_num;