1

我的桌子:

parent (id number)
 child (id number, parent_id number, allocation number)

因此,对于每个父级,子表中都有三个固定记录。而且,我需要放置一个验证块来限制用户更新子表中三个大于 100% 的子表中的任何一个的分配(对于任何给定的 parent_id)。

我添加了一个触发器来检查给定 parent_id 的分配总和,如果它大于 100%,则引发异常。然而,这导致了一个变异问题。克服此问题的任何设计改进/建议或实现此问题的任何替代方案。

样本数据

PS:应用拦截oracle异常,并在应用中翻译成红条错误信息;因此必须使用 RAISE_APPLICATION_ERROR 来显示错误消息。

编辑 1:
这里的问题是应用层,它允许在列表屏幕上进行编辑。可以一次更新多个记录,因此子表上的触发器将被多次触发。在每个触发器实例中,我们还需要检查其他孩子的分配,这会导致变异问题。

4

2 回答 2

1

您不能在定义了触发器的表上的触发器中执行 DML,您可以看到结果为 mutating trigger 错误。

一种替代方法是引入另一个表,比如 sum_parent ,您可以在其中维护每个父 id 的分配数总和,并且在子表的触发器中,您可以从该表中获取数据(sum_parent),放置检查然后更新该表( sum_parent) 与触发器本身内的新总和。

于 2014-01-01T14:18:29.157 回答
0

仅使用 DDL 的解决方案。无触发器:

CREATE TABLE child 
( id number NOT NULL, 
  parent_id  number NOT NULL,
  allocation number NOT NULL,

我们添加了一些我们需要的列:

  child_no      number NOT NULL,        -- a number from 1 to 3 
  prev_child_no number NOT NULL,        -- previous child number

  running_total      number NOT NULL,   -- running total of allocations
  prev_running_total number NOT NULL,   -- previous running total

除了你有的限制

          -- I guess you already have these two constraints        
  PRIMARY KEY (id), 
  FOREIGN KEY (parent_id)
    REFERENCES parent (id), 
  CHECK ( allocation >= 0 ),

我们添加了更多内容,用于子到前子关系:

          -- this links a child to the previous one
  FOREIGN KEY (parent_id, prev_child_no, prev_running_total)
    REFERENCES child (parent_id, child_no, running_total),

          -- these 2 constraints enforce that there are
  UNIQUE (parent_id, child_no),         -- maximum 3 children
  CHECK (child_no IN (1,2,3)),          -- per parent

          -- and this exactly 3 children per parent
  CHECK ( child_no = 1 AND prev_child_no = 3  
       OR child_no > 1 AND prev_child_no + 1 = child_no ), 

对于运行总计:

          -- this enforces that the running total is correct
  CHECK ( child_no = 1 AND running_total = allocation
       OR child_no > 1 AND running_total = allocation + prev_running_total ),

        -- enforce that it never exceeds 100
  CHECK ( running_total <= 100 )
) ;
于 2014-05-04T16:14:29.093 回答