You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

触发器编译成功但插入时触发ORA-00036递归SQL层级超限错误求助

问题原因分析

这个ORA-00036错误的根源非常直接:你的触发器TR1是BEFORE INSERT OR UPDATE ON DOCKING的行级触发器,而在触发器的逻辑里,当满足car <= cap的条件时,你又执行了一次INSERT INTO DOCKING操作。

每次执行这个INSERT语句,都会再次触发TR1本身,形成了无限递归调用:

  • 初始的INSERT INTO DOCKING触发TR1
  • TR1里的INSERT又触发TR1
  • 这个循环不断重复,直到达到Oracle默认的递归SQL层数上限(50层),抛出错误

另外还有两个小问题需要注意:

  • 触发器的WHEN条件里TO_DATE(NEW.ARRIVAL_DATE)是多余的,因为ARRIVAL_DATE本身就是DATE类型,不需要再次转换
  • 你误用了BEFORE触发器的作用:BEFORE触发器的核心是修改:NEW字段的值,Oracle会自动把修改后的:NEW数据插入到表中,手动插入完全是画蛇添足
解决方法

我们需要重构触发器的逻辑,去掉不必要的INSERT操作,改成验证拦截逻辑(如果不满足停靠条件就抛出错误阻止插入),这才是你这个触发器应该实现的核心需求——只允许船的载货量小于等于码头容量时,才允许插入DOCKING记录。

修改后的触发器代码如下:

CREATE OR REPLACE TRIGGER TR1 
BEFORE INSERT OR UPDATE ON DOCKING 
FOR EACH ROW 
WHEN (NEW.ARRIVAL_DATE <= NEW.DEPARTURE_DATE) -- 移除多余的TO_DATE转换
DECLARE
    cap PIERS.CAPACITY%TYPE;
    car SHIPS.CARGO_WIEGHT%TYPE;
BEGIN
    -- 获取对应码头的容量
    SELECT CAPACITY INTO cap 
    FROM PIERS 
    WHERE PIERS.PID = :NEW.PID;
    
    -- 获取对应船只的载货量
    SELECT CARGO_WIEGHT INTO car 
    FROM SHIPS 
    WHERE SHIPS.SID = :NEW.SID;
    
    -- 如果载货量超过码头容量,抛出自定义错误阻止操作
    IF car > cap THEN
        RAISE_APPLICATION_ERROR(-20001, '船只载货量超过码头容量,无法停靠');
    END IF;
EXCEPTION
    WHEN NO_DATA_FOUND THEN
        -- 把静默失败改成抛出错误,方便排查数据问题
        RAISE_APPLICATION_ERROR(-20002, '对应的码头或船只不存在');
END;
/

关键修改点说明:

  • 移除了触发器内部的INSERT INTO DOCKING语句,BEFORE触发器不需要手动插入数据,Oracle会自动处理:NEW行的插入/更新
  • 把原来的正向判断改成反向拦截逻辑:如果载货量超过容量,就抛出自定义错误,直接阻止非法操作
  • 优化了WHEN条件,去掉多余的类型转换
  • 改进了异常处理,把原来的静默忽略改成抛出错误,避免隐藏数据问题

现在执行你的插入语句:

INSERT INTO DOCKING VALUES(88, 5, '15-AUG-17', '15-AUG-17');

因为S8的载货量是50000,E码头的容量是60000,满足停靠条件,所以会正常插入,不会再触发递归错误。

内容的提问来源于stack exchange,提问作者Mor Goren

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:22:35