2011-05-03 21 views
2

对于学校项目,我们不得不使用触发器来更新冗余信息。我们有一个名为'recipe_ratings'的表格,其中包含'评分'(数字0-100)。在我们的“食谱”表中,我们有一个称为“评分”的冗余行,其中包含该特定配方的平均评分。Oracle使用触发器计算平均值

我们试图创建一个Oracle触发器是这样的:

CREATE OR REPLACE TRIGGER trigger_rating 
AFTER UPDATE 
    ON recipe_ratings 
    FOR EACH ROW 

DECLARE 
    average_rating NUMBER; 

BEGIN 
    SELECT ROUND(AVG(rating)) 
    INTO average_rating 
    FROM recipe_ratings 
    WHERE rid = :new.rid; 

    UPDATE recipe SET rating = average_rating 
    WHERE rid = :new.rid 

END; 

但是,这给了我们:ORA-04091:表名称变异,触发/功能可能无法看到它。我们正在尝试'自主交易',但感觉就像我们正在从我们的触发中飘走。

我们该如何使这个触发器工作?

+1

我希望这个学校项目的唯一理由是给你的经验知道,以避免像瘟疫这种冗余:) – 2011-05-04 01:03:24

回答

1

This article给出了一种避免这些错误的方法。

另一个想法 - 会是一个'正常'的触发器,比FOR EACH ROW触发器更适合在这里吗?如果在一个语句中同一配方有多个recipe_rating更新,则计算平均多次(否则为突变警告)。

4

我希望教授不会引导你使用自治事务,除了使用无效的数据模型外,这将是一个可怕的滥用自治事务的路径。

在现实世界中,为了使这种工作的事情,你需要

  • 一包RID值
  • A之前声明触发器的集合初始化此集合
  • 将new.rid值插入集合中的行级触发器
  • 通过集合读取并在RECIPE_RATINGS表上发布更新的after语句触发器

显然,这种事情很快就会变得非常繁琐,这就是为什么存储冗余数据存在问题的原因。

如果您只需处理插入操作,并且可以保证所有插入操作都是使用INSERT ... VALUES的单行插入操作,则可以在查询中查询RECIPE_RATINGS表。这在现实世界中不起作用,但在教室里可能就足够了。

如果你不介意重新计算的平均得分为每次每配方中RECIPE_RATINGS一个单行updated--的东西,将是灾难性的做法,但可以在足够小的数据set--工作你可以有一个after语句触发器,它在RECIPE表的每一行进行相关更新。

2

您的数据模型有多灵活?

您可以存储所有评分和评分数量的总和,而不是存储配方的平均评分。

评分中的插入触发器将采用值或新行更新父级配方行,以将评分添加到总数中,并将1添加到评分的数量/计数中。

更新触发器会将NEW:和OLD值之间的差值加到总数上(而不是更新计数)。

这两个触发器都不必查询评级表上的其他行,以防止发生变异表错误,并使其在具有多个并发用户的环境中使用更安全。

查询(或视图或派生列)将简单地通过总数除以计数来确定平均值。

+0

PS。如果你允许在ratigns表 – 2011-05-04 00:38:25

+0

+1上删除,你可能需要一个DELETE触发器,它会起作用(尽管很麻烦)。如果你想处理'rid'(':new.rid!=:old.rid')的更新,你也可以将更新视为DELETE + INSERT。 – 2011-05-04 12:10:34