触发检查要插入的值

时间:2018-10-12 11:19:20

标签: plsql triggers

我有两个涉及两个不同模式的表。

模式服务和表任务-列ID

Schme mona_internal和table officius_unos-列任务

我在插入列任务表officius_unos时需要触发器,以检查是否存在从表任务的列id中插入值。如果存在,则要继续插入,就不会出现该错误。

这是触发因素:

CREATE OR REPLACE TRIGGER mona_internal.PROBA_PROBA 
    BEFORE INSERT ON OFFICIUS_UNOS 
    FOR EACH ROW 
    DECLARE
        task_provera number(10);

        BEGIN
            select id into task_provera from servis.task
            where id=:new.task;

            if (task_provera is null)
                then raise_application_error(-20101, 'No task');
                else insert into mona_internal.OFFICIUS_UNOS (task) values (:new.task);
            end if;    

        END;

触发器已编译,但是尝试在列任务表officius_unos中插入新值时出现问题, 它向我返回此消息

insert into officius_unos (task) values (291504);

    Error report -
    ORA-00036: maximum number of recursive SQL levels (50) exceeded
    ORA-00036: maximum number of recursive SQL levels (50) exceeded
    ORA-06512: at "MONA_INTERNAL.PROBA_PROBA", line 5
    ORA-04088: error during execution of trigger 'MONA_INTERNAL.PROBA_PROBA'
    ORA-06512: at "MONA_INTERNAL.PROBA_PROBA", line 10

表任务的ID列中存在值291504。

P.S。也可以尝试通过检查约束来解决此问题,但是存在禁止的子查询。用来解决问题的解决方案在这里

Oracle: Using subquery in a trigger

1 个答案:

答案 0 :(得分:1)

您不需要在插入触发器中插入。

如果触发成功,Oracle将自行继续执行INSERT。

因此,直接的解决方案是从触发器中删除INSERT:

CREATE OR REPLACE TRIGGER mona_internal.PROBA_PROBA 
    BEFORE INSERT ON OFFICIUS_UNOS 
    FOR EACH ROW 
DECLARE
    task_provera number(10);
BEGIN
    select id 
       into task_provera 
    from servis.task
    where id=:new.task;

    if (task_provera is null) then 
      raise_application_error(-20101, 'No task');
    end if;
    // nothing do do here
END;

但是,以上仍然不正确。如果id中不存在servis.tak,则SELECT将抛出NO_DATA_FOUND异常。

一种解决方案是使用将始终返回一行的聚合函数。如果没有任何行符合WHERE条件,则返回NULL值:

CREATE OR REPLACE TRIGGER mona_internal.PROBA_PROBA 
    BEFORE INSERT ON OFFICIUS_UNOS 
    FOR EACH ROW 
DECLARE
    task_provera number(10);
BEGIN
    select max(id) 
       into task_provera 
    from servis.task
    where id=:new.task;

    if (task_provera is null) then 
      raise_application_error(-20101, 'No task');
    end if;
    // nothing do do here
END;

或者您可以明确地捕获异常:

CREATE OR REPLACE TRIGGER mona_internal.PROBA_PROBA 
    BEFORE INSERT ON OFFICIUS_UNOS 
    FOR EACH ROW 
DECLARE
    task_provera number(10);
BEGIN
    select max(id) 
       into task_provera 
    from servis.task
    where id=:new.task;

    if (task_provera is null) then 
      raise_application_error(-20101, 'No task');
    end if;

EXCEPTION 
   WHEN NOT_DATA_FOUND THEN 
      raise_application_error(-20101, 'No task');
END;

但是正确的方法是对此类内容使用外键约束。

alter table mona_internal.PROBA_PROBA 
   add constraint fk_proba_task
   foreign key (task)
   references servis.task (id);

那么您根本不需要触发器。

这要求不仅向用户mona_internal授予servis.task的SELECT特权,而且还授予references特权:

为此,请以SERVIS用户身份运行以下命令:

grant references on task to mona_internal;