Oracle中的语句级别/行级别之前/之后的触发器

时间:2017-04-27 22:39:03

标签: sql oracle plsql triggers

我认为这些概念对我来说很清楚,现在我不太确定。我是SQL的新手并且已经搜索了答案,但似乎太愚蠢了解无法理解可用的内容。

这是一个虚构的情况,也许我可以得到一些见解。让我们说我有一张名为注册详情的表格,其中包含学生ID,课程ID,成绩和机构。成绩通常在一个季度末分配,但如果有成绩变化,可能会在四分之一的中间更新。如果我要编写一个计算GPA的触发器......

CREATE OR REPLACE TRIGGER gpa_calc
BEFORE UPDATE OF course_grade
ON enroll_details
FOR EACH ROW

如果

,它会如何改变?
  1. 我将BEFORE改为AFTER
  2. 从FOR EACH ROW更改为声明级别。
  3. 如果我把BEFORE改为AFTER我会发生错误,因为你试图更新已经写入内存的表。

    如果我从行级别更改为语句级别触发器,我不确定GPA是否会被正确计算,因为每次更新都不会触发GPA ...

    任何帮助都将不胜感激。

2 个答案:

答案 0 :(得分:2)

documentation

在触发器可以修改正在更新/插入的数据之前,它们对于实施数据完整性规则或提供默认值非常有用。触发器在事务提交之前运行,并且不再可能进行更新。它们是进行验证或更新汇总表的正确位置,您希望确保源值不能进一步更改。

在您的示例中,gpa可能存储在单独的表中(因为它不是所采用的任何单个类的属性),因此它可能是后触发器。如果你要根据一些复杂的逻辑添加一个触发器来修改等级(例如,如果GPA> 4.0构成一个愚蠢的例子,你不能低于C)那么那将是一个触发前的触发器在表格更新之前更改成绩。

要添加,为每个正在更新的行调用FOR EACH ROW触发器(顾名思义),并且您可以访问:old和:new。无论更新了多少行,并且您无权访问单个:new或:old值,语句级别触发器将被调用一次。它适用于基于复杂条件强制执行/阻止访问(可能您不允许在晚上10点到晚上11点之间进行更新),或者可能将表标记为“脏”并需要通过稍后的批处理模式任务进行处理(例如,导出到数据)仓库)。

更多来自AskTom:difference before and after trigger in oracle

答案 1 :(得分:1)

计算值将复杂性引入模型。维护它们的成本通常超过按需计算它们的成本(取决于写入和读取之间的平衡)。但有时候这个价值对于应用来说是如此重要,我们总是需要手头上的。或许我们需要对其进行审核。我们假设GPA是其中一个属性。

所以,有关GPA的几点意见:

  1. GPA是根据所有学生的成绩计算的(因为它是平均值)。如果修改了三个等级,我们只需要计算一次新的GPA。因此,我们不想使用FOR EACH ROW触发器,因为在那种情况下会触发三次。除了运行相同计算三次的明显低效率之外,事务很可能会因Mutating Table错误而失败(因为数据库足够聪明,知道正在更改三个记录,所以我们想要哪个版本?)
  2. GPA是学生的一个属性。因此,计算GPA并不会改变enroll_details表的状态,因此BEFORE或AFTER触发器无关紧要(但见下文)。
  3. 通常我们使用BEFORE触发器来验证和符合值,应用计算的默认值以及我们想要发生的任何处理,无论是否应用了行。我们使用AFTER触发器进行处理,假设已经应用了行。计算像GPA这样的东西属于第二类。所以触发器应该是AFTER语句级触发器:

    CREATE OR REPLACE TRIGGER gpa_calc
        AFTER UPDATE OF course_grade
        ON enroll_details