一个触发器是一种声明,告诉数据库应该在执行特定的操作的时候执行特定的函数。
触发器可以附加到表和视图上。
触发器可以定义在一个
INSERT
,
UPDATE
, or
DELETE
命令之前或者之后执行,
要么是对每行执行一次,要么是对每条
SQL
语句执行一次。
如果某列在
UPDATE
语句的
SET
子句中被提及,则
UPDATE
触发器再次被触发。
触发器可以为
TRUNCATE
语句触发。
如果发生触发器事件,那么将在合适的时刻调用触发器函数以处理该事件。
在视图上,触发器可以被定义执行而不是
INSERT
,
UPDATE
或者
DELETE
操作。为了需要在视图中修改的每一行触发
INSTEAD OF
触发器。
这是触发器函数在基表下执行必要修改的责任,并且在适当情况下,返回在视图中出现的修改的行。
在执行每个
SQL
语句,
INSERT
,
UPDATE
或者
DELETE
操作之前或之后也可以定义视图上的触发器。
触发器函数必须在创建触发器之前,作为一个没有参数并且返回
trigger
类型的函数定义。
触发器函数通过特殊的
TriggerData
结构接收其输入,
而不是用普通的函数参数方式。
一旦创建了一个合适的触发器函数,
就可以用
CREATE TRIGGER
创建触发器。
同一个触发器函数可以用于多个触发器。
PostgreSQL
提供
按行
与
按语句
触发的触发器。
按行触发的触发器函数为触发语句影响的每一行执行一次;相比之下,
按语句触发的触发器函数为每条触发语句执行一次,而不管影响的行数。
特别是,一个影响零行的语句将仍然导致按语句触发的触发器执行。
这两种类型的触发器有时候分别叫做
行级
触发器和
语句级
触发器。
在
TRUNCATE
上的触发器可能只能在语句级别定义。
触发之前或之后的视图,触发器只能在语句级别定义,
然而非
INSERT
,
UPDATE
或者
DELETE
触发的触发器在行级别定义。
触发器通常按照触发的
before
和
after
,
或者
instead of
操作进行分类。
这些分别被称为
BEFORE
触发器,
AFTER
触发器,
INSTEAD OF
触发器。
语句级别的
BEFORE
触发器通常在语句开始做任何事情之前触发,
而语句级别的
AFTER
触发器在语句结束时触发。
触发器的这些类型可以在表或者视图上定义。
行级别的
BEFORE
触发器在对特定行进行操作之前触发,
而行级别的
AFTER
触发器在语句结束的时候触发
(但是在任何语句级别的
AFTER
触发器之前)。
触发器的这些类型可能只在表上定义。
行级别
INSTEAD OF
触发器可能只在视图上定义,
并且立刻触发作为视图上的每一行被标识为需要的操作。
按语句触发的触发器应该总是返回
NULL
。
如果必要,按行触发的触发器函数可以给调用它的执行者返回一行数据
(一个类型为
HeapTuple
的数值),
那些在操作之前触发的触发器有以下选择:
它可以返回
NULL
以忽略对当前行的操作。
这就指示执行器不要执行调用该触发器的行级别操作(对特定行的插入或者更改)。
只用于
INSERT
和
UPDATE
行触发器:
返回的行将成为被插入的行或者是成为将要更新的行。
这样就允许触发器函数修改将要被插入或者更新的行。
一个无意导致任何这类行为的在操作之前触发的行级触发器必须仔细返回那个被当作新行传进来的行。
也就是说,对于
INSERT
和
UPDATE
触发器而言,
是
NEW
行,
对于
DELETE
触发器而言,
是
OLD
行。
行级别
INSTEAD OF
触发器应该返回
NULL
表示它不修改来自视图的基础表的任何数据,
它应该返回传递到(
INSERT
和
UPDATE
的
NEW
行,
或者
DELETE
操作的
OLD
行
)的视图行。非空返回值用于发信号,使触发器执行视图中必要的数据修改。
这将导致计算通过这个命令递增的受影响的行数。
对于
INSERT
和
UPDATE
操作,触发器可能在返回它之前修改
NEW
行。
这将改变通过
INSERT RETURNING
或者
UPDATE RETURNING
返回的数据。
并且当视图不能完全显示所提供的同一数据时是有用的。
对于在操作之后触发的行级触发器,其返回值会被忽略,因此可以返回
NULL
。
如果多于一个触发器为同样的事件定义在同样的关系上,
触发器将按照名字的字母顺序触发。
在
BEFORE
和
INSTEAD OF
触发器的情况下,
每个触发器返回的可能已经被修改过的行成为下一个触发器的输入。
如果
BEFORE
或者
INSTEAD OF
触发器返回
NULL
,
那么对该行的操作将被丢弃并且随后的触发器也不会被触发。
一个触发器定义也可以声明一个布尔型的
WHEN
条件,用于检查触发器是否应该被触发。
在行级别触发器上,
WHEN
条件可以检查旧和/或新的列值。语句级的触发器也可以有
WHEN
条件,
尽管对其没有用。在一个
BEFORE
触发器中,
WHEN
条件只在函数正在或将被执行之前被触发执行,
因此使用
WHEN
条件实际上与在触发器开始时执行相同条件的结果是一样的。然而,
在一个
AFTER
触发器中,
WHEN
条件只有在发生更新行时才会执行,
并且决定在语句结束之后,
一个事件是否需要等待触发触发器。因此当一个
AFTER
触发器的
WHEN
条件没有返回真时,
队列中的时间不需要在语句结束后重新读取行。如果触发器只会被一些行触发时,
INSTEAD OF
触发器不支持
WHEN
条件。
通常,行的
BEFORE
触发器用于检查或修改将要插入或者更新的数据。
比如,一个
BEFORE
触发器可以用于把当前时间插入一个
timestamp
字段,
或者跟踪该行的两个元素是一致的。行的
AFTER
触发器多数用于填充或者更新其它表,
或者对其它表 进行一致性检查。这么区分工作的原因是
AFTER
触发器肯定可以看到该行的最后数值,
而
BEFORE
触发器不能;还可能有其它的
BEFORE
触发器在其后触发。
如果你没有具体的原因定义触发器是
BEFORE
或者
AFTER
,
那么
BEFORE
触发器的效率高些,
因为操作相关的信息不必保存到语句的结尾。
如果一个触发器函数执行SQL命令,而这些命令再次触发触发器,
这就是所谓的级联触发器。对级联触发器的级联深度没有明确的限制。
有可能出现级联触发器导致同一个触发器递归调用的情况;
比如,一个
INSERT
触发器可能执行一个命令,
把一个额外的行插入同一个表中,
导致
INSERT
触发器再次触发。
避免这样无穷递归的问题是触发器程序员的责任。
在定义一个触发器的时候,可以声明一些参数。
在触发器定义中包含参数的目的是允许类似需求的不同触发器调用同一个函数。
比如,可能有一个通用的触发器函数,接受两个字段名字,把当前用户放在第一个,
而当前时间戳在第二个。只要写得恰当,
那么这个触发器函数就可以和触发它的特定表无关。
这样同一个函数就可以用于有着合适字段的任何表的
INSERT
事件,
实现自动跟踪交易表中的记录创建之类的问题。
如果定义成一个
UPDATE
触发器,还可以用它跟踪最后更新的事件。
每种支持触发器的编程语言都有自己的方法让触发器函数得到输入数据。
这些输入数据包括触发器事件的类型(比如
INSERT
或者
UPDATE
)以及所有
在
CREATE TRIGGER
里面列出的参数。对于低层次的触发器,
输入数据也包括
INSERT
和
UPDATE
触发器的
NEW
和/或
UPDATE
和
DELETE
触发器的
OLD
行。
语句级别的触发器目前没有任何方法检查该语句修改的独立行。