PG中的触发器

0    650    2

Tags:

👉 本文共约9621个字,系统预计阅读时间或需37分钟。

简介

PostgreSQL 触发器是数据库的回调函数,它会在指定的数据库事件发生时自动执行/调用。

下面是关于 PostgreSQL 触发器几个比较重要的点:

  • PostgreSQL 触发器可以在下面几种情况下触发:
    • 在执行操作之前(在检查约束并尝试插入、更新或删除之前)。
    • 在执行操作之后(在检查约束并插入、更新或删除完成之后)。
    • 更新操作(在对一个视图进行插入、更新、删除时)。
  • 触发器的 FOR EACH ROW 属性是可选的,如果选中,当操作修改时每行调用一次;相反,选中 FOR EACH STATEMENT,不管修改了多少行,每个语句标记的触发器执行一次。
  • WHEN 子句和触发器操作在引用 NEW.column-name 和 OLD.column-name 表单插入、删除或更新时可以访问每一行元素。其中 column-name 是与触发器关联的表中的列的名称。
  • 如果存在 WHEN 子句,PostgreSQL 语句只会执行 WHEN 子句成立的那一行,如果没有 WHEN 子句,PostgreSQL 语句会在每一行执行。
  • BEFORE 或 AFTER 关键字决定何时执行触发器动作,决定是在关联行的插入、修改或删除之前或者之后执行触发器动作。
  • 要修改的表必须存在于同一数据库中,作为触发器被附加的表或视图,且必须只使用 tablename,而不是 database.tablename。
  • 当创建约束触发器时会指定约束选项。这与常规触发器相同,只是可以使用这种约束来调整触发器触发的时间。当约束触发器实现的约束被违反时,它将抛出异常。

创建触发器语法

创建触发器时的基础语法如下:

在这里,event_name 可以是在所提到的表 table_name 上的 INSERT、DELETE 和 UPDATE 数据库操作。您可以在表名后选择指定 FOR EACH ROW。

以下是在 UPDATE 操作上在表的一个或多个指定列上创建触发器的语法:

实例

让我们假设一个情况,我们要为被插入到新创建的 COMPANY 表(如果已经存在,则删除重新创建)中的每一个记录保持审计试验:

为了保持审计试验,我们将创建一个名为 AUDIT 的新表。每当 COMPANY 表中有一个新的记录项时,日志消息将被插入其中:

在这里,ID 是 AUDIT 记录的 ID,EMP_ID 是来自 COMPANY 表的 ID,DATE 将保持 COMPANY 中记录被创建时的时间戳。所以,现在让我们在 COMPANY 表上创建一个触发器,如下所示:

auditlogfunc() 是 PostgreSQL 一个程序,其定义如下:

现在,我们开始往 COMPANY 表中插入数据:

这时,COMPANY 表中插入了一条记录:

同时, AUDIT 表中也插入了一条记录,因为我们在插入 COMPANY 表时创建了一个触发器。相似的,我们也可以根据需求在更新和删除时创建触发器:

CREATE TRIGGER — 定义一个新触发器

大纲

描述

CREATE TRIGGER创建一个新触发器。该触发器将被关联到指定的表、视图或者外部表并且在表上发生特定操作时将执行指定的函数function_name

该触发器可以被指定为在一行上尝试该操作之前触发(在约束被检查并且INSERTUPDATE或者DELETE被尝试之前);也可以在该操作完成之后触发(在约束被检查并且INSERTUPDATE或者DELETE完成之后);或者取代该操作(在对一个视图插入、更新或删除的情况中)。如果该触发器在事件之前触发或者取代事件,该触发器可以跳过对当前行的操作或者改变正在被插入的行(只对INSERT以及UPDATE操作)。如果该触发器在事件之后触发,所有更改(包括其他触发器的效果)对该触发器“可见”。

一个被标记为FOR EACH ROW的触发器会对该操作修改的每一行都调用一次。例如,一个影响 10 行的DELETE将导致在目标关系上的任何ON DELETE触发器被独立调用 10 次,也就是为每一个被删除的行调用一次。与此相反,一个被标记为FOR EACH STATEMENT的触发器只会为任何给定的操作执行一次,不管该操作修改多少行(特别地,一个修改零行的操作将仍会导致任何可用的FOR EACH STATEMENT触发器被执行)。

被指定为要触发INSTEAD OF触发器事件的触发器必须被标记为FOR EACH ROW,并且只能被定义在视图上。一个视图上的BEFOREAFTER触发器必须被标记为FOR EACH STATEMENT

此外,触发器可以被定义成为TRUNCATE触发,但只能是FOR EACH STATEMENT

下面的表格总结了哪些触发器类型可以被用在表、视图和外部表上:

何时事件行级语句级
BEFOREINSERT/UPDATE/DELETE表和外部表表、视图和外部表
TRUNCATE
AFTERINSERT/UPDATE/DELETE表和外部表表、视图和外部表
TRUNCATE
INSTEAD OFINSERT/UPDATE/DELETE视图
TRUNCATE

还有,一个触发器定义可以指定一个布尔的WHEN条件,它将被测试来看看该触发器是否应该被触发。在行级触发器中,WHEN条件可以检查该行的列的新旧值。语句级触发器也可以有WHEN条件,尽管该特性对于它们不是很有用(因为条件不能引用表中的任何值)。

如果有多个同种触发器被定义为相同事件触发,它们将按照名称的字母表顺序被触发。

CONSTRAINT选项被指定,这个命令会创建一个约束触发器。这和一个常规触发器相同,不过触发该触发器的时机可以使用SET CONSTRAINTS调整。约束触发器必须是表上的AFTER ROW触发器。它们可以在导致触发器事件的语句末尾被引发或者在包含该语句的事务末尾被引发。在后一种情况中,它们被称作是被延迟。一个待处理的延迟触发器的引发也可以使用SET CONSTRAINTS立即强制发生。当约束触发器实现的约束被违背时,约束触发器应该抛出一个异常。

REFERENCING选项启用对传递关系的收集,传递关系是包括被当前SQL语句插入、删除或者修改的行的行集合。这个特性让触发器能看到该语句做的事情的全局视图,而不是一次只看到一行。仅对非约束触发器的AFTER触发器允许这个选项。此外,如果触发器是一个UPDATE触发器,则它不能指定column_name列表。OLD TABLE仅可以被指定一次,并且只能为在UPDATEDELETE事件上引发的触发器指定,它创建的传递关系包含有该语句更新或删除的所有行的前映像。类似地,NEW TABLE仅可以被指定一次,并且只能为在UPDATEINSERT事件上引发的触发器指定,它创建的传递关系包含有该语句更新或插入的所有行的后映像

SELECT不修改任何行,因此你无法创建SELECT触发器。规则和视图可以为需要SELECT触发器的问题提供可行的解决方案。

关于触发器的更多信息请见第 38 章

本人提供Oracle(OCP、OCM)、MySQL(OCP)、PostgreSQL(PGCA、PGCE、PGCM)等数据库的培训和考证业务,私聊QQ646634621或微信db_bao,谢谢!
PG中的触发器后续精彩内容已被小麦苗无情隐藏,请输入验证码解锁本站所有文章!
验证码:
请先关注本站微信公众号,然后回复“验证码”,获取验证码。在微信里搜索“DB宝”或者“www_xmmup_com”或者微信扫描右侧二维码都可以关注本站微信公众号。

标签:

Avatar photo

小麦苗

学习或考证,均可联系麦老师,请加微信db_bao或QQ646634621

您可能还喜欢...

发表回复

嘿,我是小麦,需要帮助随时找我哦。
  • 18509239930
  • 个人微信

  • DB宝
  • 个人邮箱
  • 点击加入QQ群
  • 个人微店

  • 回到顶部