2013-09-24 45 views
0

我有一个奇怪的业务需求,让我难倒了。一些背景:基本上,我有两张用于跟踪程序增强的表格:增强和Bug。 Enhancement-> Bug的关系是1:m,Bug表有一个外键列EnhancementID。数据库设计:基于另一个表的状态

这两个表都有一个“状态”列,但这是棘手的地方。我的要求是增强的状态取决于其相关的错误。例如,如果我们有3个增强ID为100的错误和“正在测试”状态,则增强100的状态应该自动设置为“正在测试”。有几个这样的状态规则。

这个数据库由几个应用程序共享,所以我的第一个想法是在Bug表上使用“On Update”触发器。因为触发器在触发表中有Select语句,所以我收到了一个“mutating table”错误(当触发器触发时,我必须查询具有指定EnhancementID的所有错误的状态)。现在,我试图实现一个三触发器解决方案,如下所示:http://asktom.oracle.com/pls/asktom/ASKTOM.download_file?p_file=6551198119097816936但我越来越担心在数据库触发器中放置如此​​多的逻辑。

所以我的问题是:我是否合理地接近这个问题?有人可以建议更好的方法吗?也许使用增强状态的视图?

回答

5

使用视图。

没有简单的方法来同步跨行/表的数据。正如您发现触发器会导致错误发生变化并且是不可数的错误的来源。如果你想避免变异错误,看看这个workaround by Tom Kyte(这可能会帮助你理解触发器在这种情况下不是最好的工具)。

你可以使用应用程序或PL/SQL API,但请注意,如果你使用他们所有的时间(这意味着你永远不会发出一个直接更新到这些表),他们只会工作。忘记使用API​​的单个开发人员会使数据不同步。就我个人而言,如果状态非常复杂以便即时计算视图在性能方面不可接受,我只会考虑API。

由于这是冗余信息(增强的状态可以从它的错误的地位完全扣除),就不需要将其存储在一个数据库列。

如果你可以表达你的SQL查询规则,这很简单,例如:

CREATE OR REPLACE VIEW enhancement_with_status_v AS 
SELECT e.*, 
     CASE WHEN COUNT(DECODE(b.status, 'T', 1)) >= 1 THEN 'T' 
      WHEN ... 
      ELSE ... 
     END status 
    FROM enhancement e, 
    LEFT JOIN bugs b ON b.enhancement_id = e.enhancement_id 
GROUP BY e... 

如果规则太复杂,你可以写一个PL/SQL函数从SQL调用这个函数。

该视图还具有当规则更改(如大多数规则那样)时的优点,您不需要更新整个表。

+0

我实际上是根据Tom Kyte提供的解决方案中的建议来构建触发器。另一个问题是,我无法真正改变应用程序以使用当前增强表中的不同表格。根据这个视图是否可以更新增强表的状态? – user2811300

+0

所以你正试图解决带有触发器的应用程序,那一定是......不愉快!你可以重新命名你的表格并调用视图“增强”,但这可能会引发更多的问题。实际上,如果您无法控制应用程序,意想不到的后果将很难预测。 –

+0

同意@VincentMalgrat - 如果可以,请使用视图。除非你有某种形式的锁定(建议的基于触发器的解决方法没有),基于触发器的方法无法正常工作 - 基本问题是触发器无法“看见”其他事务所做的更改(如添加或更新状态为“正在测试”的另一个错误)。 –

0

this类似的东西可能有效。

尝试在更新后触发一次,以检查每个增强的不同状态并更新增强中的相同状态。

+0

我认为这与我在第一次尝试时所尝试的类似,其中我在触发器中使用SELECT时收到“变异表”错误。 – user2811300

+0

如果您尝试在更新表a后更新表b,为什么要面对变异表错误? – SriniV

+0

因为我必须查询触发器中的表a以确定表b上的状态更新。这会导致突变表错误。 – user2811300

0

我看到了两个解决方案。

  1. 数据库触发器中的问题
  2. 使用应用程序的手动更新父状态(增强的状态)提及。不要忘记在子表中索引外键,否则在分布式应用系统中死锁是不可避免的。
+0

谢谢,但使用应用程序并不是真正的选择:数据库在少数应用程序之间共享。 – user2811300