Plsql 用于检查插入值的触发器

Plsql 用于检查插入值的触发器,plsql,triggers,Plsql,Triggers,这里有两个表,它们来自两个不同的模式 架构服务和表任务-列ID Schme mona_内部和表officius_unos-列任务 在列任务表OFFICUS_unos中插入时需要触发器,以检查是否存在从表任务插入列id中的值。如果存在,则要继续插入,则不存在引发错误 触发因素如下: CREATE OR REPLACE TRIGGER mona_internal.PROBA_PROBA BEFORE INSERT ON OFFICIUS_UNOS FOR EACH ROW

这里有两个表,它们来自两个不同的模式

架构服务和表任务-列ID

Schme mona_内部和表officius_unos-列任务

在列任务表OFFICUS_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;
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;
触发器已编译,但尝试在列任务表OFFICUS_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
和值291504存在于列id的表任务中

另外,还尝试使用check约束来解决此问题,但存在禁止的子查询。我用来解决问题的方法就在这里


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

如果触发成功,Oracle将自行继续插入

因此,立即的解决方案是从触发器中移除插入:

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;
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;
然而,上述观点仍然不正确。如果servis.tak中不存在该id,则SELECT将抛出“未找到数据”异常

一种解决方案是使用一个始终返回一行的聚合函数。如果没有与WHERE条件匹配的行,则返回空值:

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用户运行以下命令:


else在mona_internal.OFFICIUS_UNOS任务值中插入:new.task;不需要。这就是错误的原因为什么不使用外键约束呢?伙计,非常感谢你的详细解释,你给我澄清了一个新的问题,这让我很困扰