【问题标题】:validation using the same table使用同一张表进行验证
【发布时间】:2014-01-18 23:43:17
【问题描述】:

我的桌子:

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

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

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

Sample data

PS:app拦截oracle异常,并将其翻译成 应用程序中的红条错误消息;因此 RAISE_APPLICATION_ERROR 是显示错误信息所必需的。

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

【问题讨论】:

  • 不管怎样,这里得到了更多的指点..类似的问题陈述link
  • 数字3真的固定了吗? parent 表中的每一行在 child 表中是否正好有 3 个相关行?

标签: oracle validation triggers mutating-table


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

    仅使用 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 )
    ) ;
    

    【讨论】:

      猜你喜欢
      • 2017-11-15
      • 2014-05-23
      • 1970-01-01
      • 1970-01-01
      • 2021-10-06
      • 2021-06-24
      • 2016-04-15
      • 1970-01-01
      • 2020-03-04
      相关资源
      最近更新 更多