【问题标题】:Saving a PL/SQL exception and raising it later?保存 PL/SQL 异常并在以后引发?
【发布时间】:2016-02-13 19:11:20
【问题描述】:

我有一个尝试插入一些数据的 PL/SQL 过程(在 Oracle 12c 数据库中)。如果失败,它应该检查一个表,看看它是否可以在那里找到一些信息来帮助解决问题。如果它找到信息一切都很好,如果不是它应该重新引发错误。

这是我的代码:

BEGIN
  -- Try to insert some data.
  INSERT INTO table VALUES x;
EXCEPTION
  WHEN OTHERS THEN
    BEGIN
      -- Check a table to fins some info to help solve the problem.
      -- If we find a row here, we can fix it.
      -- If not, we should reraise the error.
      SELECT * INTO y FROM table WHERE a = b;
      -- Do some more stuff here to fix the problem.
    EXCEPTION
      WHEN NO_DATA_FOUND THEN
        -- We could not find anything in the table,
        -- so we could not handle the situation.
        -- Reraise the error.
        RAISE;
    END;
END;

这里的问题是RAISE; 语句引发了最新的异常,即SELECT 语句引发的NO_DATA_FOUNDINSERT 的原始异常在堆栈中更靠后,但不在顶部。

我可以以某种方式“保存”来自INSERT 的错误并重新提出它吗?或者我可以运行一个SELECT INTO,如果它什么也没找到,它不会抛出错误?我的目标是重新引发原始的 INSERT 异常,而不会留下任何 NO_DATA_FOUND 异常的痕迹。

编辑:请参阅 cmets 了解为什么这不是重复的。

【问题讨论】:

  • 插入中可能出现的问题以及之后如何更正。你不能在出错之前检查吗?
  • 我试图避免在问题中提供太多上下文以专注于问题。我想做的是在违反某些外键约束时进行一些日志记录,并在发生这种情况时生成自定义错误消息。自定义错误消息来自表,我对违反的外键约束进行搜索。
  • 感谢您查看我的问题,@Stawros!这不是重复的。您建议的问题的解决方案是简单地使用RAISE。我已经这样做了,但我想提出原始错误,而不是在异常块中引起的错误。
  • 你总是可以在最后重试插入,让它再次失败。

标签: oracle plsql exception-handling oracle12c


【解决方案1】:

raise 语句从块中拉出以尝试解决问题。如果您需要重新引发修复失败的情况,请在内部异常处理程序中设置一个标志,并仅在该标志为真时执行raise

作为代码:

DECLARE
   b_reraise BOOLEAN := FALSE;
BEGIN
  -- Try to insert some data.
  INSERT INTO table VALUES x;
EXCEPTION
  WHEN OTHERS THEN
    BEGIN
      -- Check a table to fins some info to help solve the problem.
      -- If we find a row here, we can fix it.
      -- If not, we should reraise the error.
      SELECT * INTO y FROM table WHERE a = b;
      -- Do some more stuff here to fix the problem.
    EXCEPTION
      WHEN NO_DATA_FOUND THEN
        -- We could not find anything in the table,
        -- so we could not handle the situation.
        -- Reraise the error.
        b_reraise := TRUE;
    END;

    IF b_reraise THEN
        RAISE;
    END IF;
END;

【讨论】:

  • 附带说明,当我将外部EXCEPTION 中的部分放入存储过程以在其他地方重用时,这似乎不起作用。然后我不能从程序中调用RAISE,因为它不在异常中。但它现在解决了我的问题和我提出的问题,所以接受了答案。
  • 您总是可以用额外的BEGIN..EXCEPTION... END; 括起您的代码,所以应该可以。
【解决方案2】:

可能是这样的:

DECLARE
  l_sqlerrm  VARCHAR2(4000);
  l_sqlerrc  NUMBER;
  l_exc      EXCEPTION;
BEGIN
  -- some code with errors
EXCEPTION
  WHEN OTHERS THEN
    l_sqlerrm := SQLERRM;
    l_sqlerrc := SQLCODE;
    -- loggin
    INSERT INTO my_log (code, text) VALUES (l_sqlerrc, l_sqlerrm);
    COMMIT;
    -- some your code "Check a table to fins some info to help solve the problem"
    -- some code to SELECT code INTO l_sqlerrc FROM my_log
    PRAGMA exception_init(l_exc, l_sqlerrc);
    RAISE l_exc;
END;

【讨论】:

  • PRAGMA exception_init 的第二个参数不能是变量,所以我认为这种方法行不通。不过有趣的想法。
  • @MatthewMcPeak 嗯...但是为什么它会起作用呢?创建表 t1(ID 号码主键);插入 t1 值 (1);犯罪;声明 l_sqlerrm VARCHAR2(4000); l_sqlerrc NUMBER; l_tmp 号码; l_exc 异常;开始插入 t1 值 (1);犯罪;其他情况除外 l_sqlerrm := SQLERRM; l_sqlerrc := SQLCODE; PRAGMA exception_init(l_exc, l_sqlerrc); BEGIN SELECT id INTO l_tmp FROM t1 WHERE 1 = 2;当 NO_DATA_FOUND THEN RAISE l_exc 时出现异常;结尾;结束;
  • 尝试在第二个参数中使用变量可能会导致 PLS-00702 错误。阅读 Oracle 关于该错误的文档 - 很明显(来自那个来源)他们不期望或支持该位置的变量,即使它在您的示例中有效。如果没有先用 Oracle 记录 SR 以验证它是否受支持,我不会将其用于生产代码。因为可以使用但不受支持的东西在以后的版本中可能无法使用。
  • 我还要指出,您的代码具有完全相同的功能没有 PRAGMA。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-14
  • 1970-01-01
  • 2021-11-29
  • 2013-02-05
  • 1970-01-01
相关资源
最近更新 更多