Oracle 触发器 - 变异表的问题

标签 oracle triggers ora-04091 mutating-table

我的表:

TableA (id number, state number)
TableB (id number, tableAId number, state number)
TableC (id number, tableBId number, state number)

所以表C 中的项是表B 的子项,而表B 中的项是表A 的子项。反之亦然 - TableA 中的项是 TableB 的父项,TableB 中的项是 TableC 的父项。

我想控制父项的状态……例如,我们有以下数据:
TableA (id, state): 
1, 40

TableB (id, tableAId, state): 
1, 1, 40
2, 1, 60

TableC (id, tableBId, state): 
1, 1, 40
2, 1, 50
3, 2, 60
4, 2, 70

父状态应该始终是他 child 的最小状态。因此,如果我们现在像这样更新 TableC:
update TableC set state = 50 where Id = 1;

我的触发器应该自动更新 TableB(设置状态 = 50,其中 id = 1),然后也更新 TableA(设置状态 = 50,其中 id = 1)

我想用触发器(更新后,插入,删除,在表A,表B,表C上)来做到这一点,以便在每个操作之后执行这些步骤:
  • 获取父 ID
  • 从当前父节点的所有子节点中找到最小的状态
  • 如果所有子节点的最小状态大于父节点的状态,则更新父节点

  • 如何避免“变异表错误”?在这个例子中使用自治事务是否省钱?我看到了一些意见,变异表错误表明应用程序逻辑存在缺陷 - 这是真的,我该如何更改逻辑以防止出现此错误?

    谢谢

    编辑:
    感谢所有伟大的答案!

    最后,我使用了触发器(感谢 Vincent Malgrat,他指出了 Tom Kyte 的文章)。

    编辑:
    在 REAL END 中,我使用了存储过程并删除了触发器:)

    最佳答案

    正如您已经注意到的那样,很难用触发器来满足您的业务需求。原因是Oracle 5 月 为单个查询(并行 DML)同时更新/插入多个线程的表。这意味着您的 session 无法查询它更新的表 更新发生时 .

    如果您真的想使用触发器执行此操作,则必须遵循 kind of logic shown in this article by Tom Kyte .如您所见,这并不简单。

    还有另一种更简单、更优雅、更易于维护的方法:使用过程。撤销应用程序用户的更新/插入权限,并编写一组允许应用程序更新状态列的过程。

    这些过程将锁定父行(以防止多个 session 修改同一组行),并将以高效、可读和易于维护的方式应用您的业务逻辑。

    关于Oracle 触发器 - 变异表的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2138363/

    相关文章:

    sql - 在 rank() over 之后只选择 3 个排名最好的

    sql - 如何从oracle中删除多边形中的洞

    sql - 如何在Oracle 10g中执行 "selective where"?

    mysql - 在 SQL 中声明变量的正确方法是什么?

    sql-server - 在 SQL 2005 或 2008 中是否可以在还原时触发数据库

    Oracle 删除触发器后...如何避免变异表 (ORA-04091)?

    更新列的 SQL 语句

    postgresql - 如何将值从更改的行发送到 postgres 中的触发器?

    sql - 删除与 LIKE 子字符串匹配的行?

    Oracle 使用触发器计算平均值