Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/oracle/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Oracle使用触发器计算平均值_Oracle_Triggers_Ora 04091 - Fatal编程技术网

Oracle使用触发器计算平均值

Oracle使用触发器计算平均值,oracle,triggers,ora-04091,Oracle,Triggers,Ora 04091,对于学校项目,我们被迫拥有冗余信息,并使用触发器进行更新。我们有一个名为“配方评分”的表,其中包含一个“评分”(数字0-100)。在“菜谱”表中,我们有一个称为“评级”的冗余行,其中包含特定菜谱的平均评级 我们尝试创建如下Oracle触发器: CREATE OR REPLACE TRIGGER trigger_rating AFTER UPDATE ON recipe_ratings FOR EACH ROW DECLARE average_rating NUMBER;

对于学校项目,我们被迫拥有冗余信息,并使用触发器进行更新。我们有一个名为“配方评分”的表,其中包含一个“评分”(数字0-100)。在“菜谱”表中,我们有一个称为“评级”的冗余行,其中包含特定菜谱的平均评级

我们尝试创建如下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:表名正在变化,触发器/函数可能看不到它。我们正在尝试“自主交易”,但感觉好像我们正在偏离触发点

如何使触发器工作?

提供了一种避免这些错误的方法


另一个想法是,“正常”触发器比“每行一个”触发器更适合这里吗?如果在一条语句中对同一配方有多个配方分级更新,则您将多次计算平均值(因此出现变异警告).

我希望教授没有引导你走上使用自治事务的道路,除了使用无效的数据模型之外,这将是对自治事务的可怕滥用

在现实世界中,为了让这类事情起作用,你需要

  • 包含RID值集合的包
  • 初始化此集合的before语句触发器
  • 将:new.rid值插入集合的行级触发器
  • after语句触发器,读取集合并在
    RECIPE\u RATINGS
    表上发布更新
显然,这类事情很快就会变得相当麻烦,这就是为什么存储冗余数据是如此困难的原因

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


如果您不介意每次更新
recipe\u RATINGS
中的一行时重新计算每个配方的平均评级,这在实践中可能是灾难性的,但可能在足够小的数据集上工作,那么您可以使用after语句触发器对
配方的每一行进行相关更新表。

您的数据模型有多灵活

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

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

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

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


查询(或视图或派生列)只需将总数除以计数即可确定平均值。

PS。您可能需要一个删除触发器,以确保如果您允许删除ratigns表+1,它将起作用(尽管很麻烦)。如果你想处理
rid
:new.rid!=:old.rid
)上的更新,也可以将更新视为删除+插入。我希望这个学校项目的唯一原因是给你经验,避免像瘟疫一样的冗余:)