当尝试将数据插入表格时,它可能会因违反唯一密钥或违反外键等各种原因而失败。
我可以使用DUP_VAL_ON_INDEX异常来知道违反了唯一密钥但是如果有多个具有唯一标记的列,我怎么知道哪个密钥?在这种情况下我应该使用触发器吗?
(我使用异常驱动存储过程流而不是查询表以确保插入的数据没问题。)
答案 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)
对于它的价值,我建议您不仅依靠应用程序代码来强制执行唯一性。一个关键(双关语)的原因是很难编写能够正确执行此操作的代码,特别是对于在多个事务中同时插入或更新数据的情况。声明数据库将正确有效地执行的唯一约束相对简单。
如果你想知道哪些列违反了一个独特的约束,一种方法(我意识到它不是“漂亮”)是:
SQLERRM
返回)。如果您想知道哪些行违反了唯一约束,您可以使用LOG ERRORS INTO
语句的INSERT
子句将有问题的行记录到错误记录中表,如this example中所述。
如果您想知道哪些行和列违反了唯一约束,您可以组合使用这两种方法 - 使用LOG ERRORS INTO
子句记录行,然后解析来自错误消息的constaint名称(也记录在错误记录表中)并查找相应的列。
话虽如此,您不一定需要在以下两者之间做出选择:a)首先检查数据,只有在通过检查时才插入数据,b)尝试插入数据,然后报告和/或采取行动任何错误。