Oracle使用触发器计算平均值
对于学校项目,我们被迫拥有冗余信息,并使用触发器进行更新。我们有一个名为“配方评分”的表,其中包含一个“评分”(数字0-100)。在“菜谱”表中,我们有一个称为“评级”的冗余行,其中包含特定菜谱的平均评级 我们尝试创建如下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;
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
)上的更新,也可以将更新视为删除+插入。我希望这个学校项目的唯一原因是给你经验,避免像瘟疫一样的冗余:)