Oracle - 我应该使用异常或触发器吗?

时间:2012-11-27 00:18:37

标签: oracle triggers oracle11g oracleexception

当尝试将数据插入表格时,它可能会因违反唯一密钥或违反外键等各种原因而失败。

我可以使用DUP_VAL_ON_INDEX异常来知道违反了唯一密钥但是如果有多个具有唯一标记的列,我怎么知道哪个密钥?在这种情况下我应该使用触发器吗?

(我使用异常驱动存储过程流而不是查询表以确保插入的数据没问题。)

3 个答案:

答案 0 :(得分:0)

例外(来自约束)或触发器?我也不说。

强烈建议使用应用程序代码和查询来驱动应用程序的逻辑,而不是触发器和约束。将逻辑与错误条件处理分开只会使代码的行为看起来更加神奇。

虽然约束作为备份计划非常有用(在应用程序逻辑错误或更改的情况下),但您是正确的,因为它们无法以您希望的方式协助运行时错误处理(即不帮助您公开INSERT语句尝试使用的重复键。

毫无疑问,您可以非常轻松地使用触发器来执行您所描述的内容,但最终所有这些意味着您只是隐藏相同的逻辑测试(“此记录是否已存在?”)触发器,而不是应用程序代码中存在INSERT语句的触发器。如果表中存在多个触发器,那么<​​em>可能也会不必要地执行它们的开销,就好像会引发错误一样,任何其他先行的错误都会毫无结果。

如果您不想在运行新的INSERT语句之前编写其他语句来预先检查数据的状况,那么我建议使用以下内容:

  INSERT INTO my_table (col1, col2)
  SELECT l_val1, l_val2
  FROM dual
  WHERE NOT EXISTS (
    SELECT 1
    FROM my_table t
    WHERE t.col1 = l_val1
    AND t.col2 = l_val2
  )

至少那时你不会违反密钥,但是你会通过测试SQL%ROWCOUNT是否为0(没有插入行,所以必须已存在)或1来知道是否已经存在一行。

但是,这仍然没有为您提供密钥违规值。您必须编写查询以找出违反约束的内容。

答案 1 :(得分:0)

这不是触发器的用途。请记住,您can not query the target table inside a trigger,因此您无法真正检查唯一性违规行为。我想说触发器的最佳原因是确保使用默认数据填充行,例如序列中的id。触发器也会混淆代码,因为不清楚为什么插入的行与您的语句不同。

约束执行除明显之外的有用功能:优化器可以使用约束中的信息来判断执行计划。例如,如果优化器知道列是否为NULL,则可以计算更有效的路由。

上面@Ben给出的INSERT语句很好,你也可以将你的语句包装在匿名块中:

BEGIN
    ... application code ... 
    BEGIN
        INSERT INTO mytable (col1, col2) VALUES (val1, val2);
    EXCEPTION WHEN DUP_VAL_ON_INDEX THEN
        ... error handling code ...
    END;
    ... application continues...
END;

答案 2 :(得分:0)

对于它的价值,我建议您仅依靠应用程序代码来强制执行唯一性。一个关键(双关语)的原因是很难编写能够正确执行此操作的代码,特别是对于在多个事务中同时插入或更新数据的情况。声明数据库将正确有效地执行的唯一约束相对简单。

如果你想知道哪些违反了一个独特的约束,一种方法(我意识到它不是“漂亮”)是:

  1. 从错误消息中解析约束名称(例如,由SQLERRM返回)。
  2. 使用某种机制(如数据字典或您自己的表)来“查找”哪些列对应于约束。
  3. 如果您想知道哪些违反了唯一约束,您可以使用LOG ERRORS INTO语句的INSERT子句将有问题的行记录到错误记录中表,如this example中所述。

    如果您想知道哪些行列违反了唯一约束,您可以组合使用这两种方法 - 使用LOG ERRORS INTO子句记录行,然后解析来自错误消息的constaint名称(也记录在错误记录表中)并查找相应的列。

    话虽如此,您不一定需要在以下两者之间做出选择:a)首先检查数据,只有在通过检查时才插入数据,b)尝试插入数据,然后报告和/或采取行动任何错误。

相关问题