Oracle 异常未在触发器中捕获

Posted

技术标签:

【中文标题】Oracle 异常未在触发器中捕获【英文标题】:Oracle exception not caught in trigger 【发布时间】:2019-07-15 03:05:46 【问题描述】:

我正在尝试捕获 ORA-02292 child record found 异常,而不是使用我自己的消息引发自定义异常。

这是我的简单触发器:

CREATE OR REPLACE TRIGGER modifOuSuppressionSucc
BEFORE DELETE OR UPDATE ON Succursale
FOR EACH ROW
BEGIN
    IF DELETING THEN
        UPDATE Projet SET NumSuccursale = NULL
        WHERE NumSuccursale = :OLD.NumSuccursale;
    ELSE
        IF UPDATING AND :NEW.NumSuccursale!=:OLD.NumSuccursale THEN
            UPDATE Projet SET NumSuccursale = :NEW.NumSuccursale
            WHERE NumSuccursale = :OLD.NumSuccursale;
        END IF;
    END IF;

    EXCEPTION
        WHEN OTHERS THEN
            RAISE_APPLICATION_ERROR(-20010, 'La modification ou la suppression d''une succursale n''est pas possible. Erreur '||SQLCODE||' -ERREUR- '||SQLERRM);
END;

当我尝试使用以下命令删除父表中的行时,Oracle 会引发 -02292 异常(这是正确的),但 WHEN OTHERS THEN 子句不会引发我的自定义异常。

DELETE Succursale  WHERE NumSuccursale=4;

我收到标准的ORA-02292 child record found 消息:

Erreur commençant à la ligne: 48 de la commande -
DELETE Succursale  WHERE NumSuccursale=4
Rapport d'erreur -
ORA-02292: violation de contrainte (HB691016.SYS_C003806517) d'intégrité - enregistrement fils existant

而不是我的-20010 自定义错误消息。

我需要改变什么才能让它正确?

【问题讨论】:

我试图重现您的场景,但无法重现。您能否在我的example 中分享可重现的示例 您只捕获触发代码引发的异常,此处抛出的实际异常与此触发代码无关。您可能应该验证与触发器中的约束(在 SUCCURSALE 表上)相关的数据完整性,如果不满足条件则抛出错误。 没有得到您在最后一条评论中所传达的内容 - 请参阅Example。没有触发器,它会抛出一个错误,WITH TRIGGER,它不会抛出一个错误。如果您在谈论其他内容,请编辑 db fiddle 并分享已编辑的 db fiddle 的 URL 【参考方案1】:

触发器不适用于此。如果您必须在父表中删除不受您控制的删除,那么拥有FOREIGN KEY 并不是一个好设计。

您可以使用DEFERRABLE Clause 作为您的约束。这允许您在提交事务之前在单个语句中运行删除和更新。

 ALTER TABLE Projet ADD CONSTRAINT fk_succurscale foreign key(NumSuccursale)
          references Succursale(NumSuccursale) initially deferred deferrable

这是它如何工作的说明。

declare
l_del Succursale.NumSuccursale%TYPE := 3;

l_upd_from Succursale.NumSuccursale%TYPE := 4;
l_upd_to Succursale.NumSuccursale%TYPE := 3;
BEGIN
DELETE Succursale  WHERE NumSuccursale=l_del;
UPDATE Projet   SET  NumSuccursale=NULL WHERE NumSuccursale=l_del;
COMMIT;--Constraint checking won't happen until this commit is issued.

UPDATE Succursale SET  NumSuccursale=l_upd_to WHERE NumSuccursale=l_upd_from;
UPDATE Projet SET  NumSuccursale=l_upd_to WHERE NumSuccursale=l_upd_from;
COMMIT;

END;
/

上述区块的DEMO

【讨论】:

以上是关于Oracle 异常未在触发器中捕获的主要内容,如果未能解决你的问题,请参考以下文章

如果在更新触发之前未在 oracle 中进行更新,则新值与旧值相同

oracle触发器疑问

单击事件未在引导单选按钮组中触发

捕获到 SQL 异常。错误是:ORA-04098:触发器无效并且重新验证失败

在ORACLE触发器中想使用into 语句给一个变量赋值,但是查询出来的值可能为空,如何避免报错未找到任何数据

如何在 Oracle PL/SQL 上创建可以捕获 DUP_VAL_ON_INDEX 的前触发器或后触发器