我创建了如下所示:
table
,person
- 一个名为
log
的table
,其中插入了一行。 my_v
view
trigger function
称为my_func()
,其目的是将num.log
增加1
。- 一个名为
my_t
的trigger
,它在my_v
上执行my_func()
before
each statement
(INSERT
,UPDATE
或DELETE
)。
CREATE TABLE person (
name VARCHAR(20)
);
CREATE TABLE log (
num INTEGER
);
INSERT INTO log (num) VALUES (0);
CREATE VIEW my_v AS
SELECT * FROM person;
CREATE FUNCTION my_func() RETURNS trigger
AS $$
BEGIN
UPDATE log SET num = num + 1;
RETURN NULL;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER my_t BEFORE INSERT OR UPDATE OR DELETE ON my_v
FOR EACH STATEMENT EXECUTE FUNCTION my_func();
字符串
另外,我还测试了trigger
my_t
执行after
each statement
的情况
CREATE TRIGGER my_t AFTER INSERT OR UPDATE OR DELETE ON my_v
FOR EACH STATEMENT EXECUTE FUNCTION my_func();
型
通过这种设置,表log
中的num
的值预计会计算my_func()
被触发器调用的次数。
在my_v
中插入、更新或删除行时,log.num
仍为0
。请参阅下面的语句,最后一个语句是对表log
的检查(* 实际上在每次操作后进行了测试,但为了缩短问题,从此处删除 *):
postgres=# INSERT INTO my_v (name) VALUES ('John');
INSERT 0 1 /* -> 1 row successfully inserted */
postgres=# UPDATE my_v SET name = 'Tom';
UPDATE 1 /* -> 1 row successfully updated */
postgres=# DELETE FROM my_v;
DELETE 1 /* -> 1 row successfully deleted */
postgres=# SELECT num FROM log;
num
-----
0
(1 row)
型
因此,视图上带有BEFORE
或AFTER
和INSERT
、UPDATE
或DELETE
的触发器在PostgreSQL中不起作用。
重要提示:my_t
触发器的另一个版本INSTEAD OF
和FOR EACH ROW
可以正常工作:
CREATE TRIGGER my_t INSTEAD OF INSERT OR UPDATE OR DELETE ON my_v
FOR EACH ROW EXECUTE FUNCTION my_func();
型
如何创建my_t
触发器,在my_v
上发生INSERT
,UPDATE
或DELETE
操作之前或之后触发my_func()
?
1条答案
按热度按时间hc2pp10m1#
这是设计出来的,虽然不是很明显,但它是有文档记录的。Views 上的BEFORE / AFTER触发器只支持那些具有INSTEAD OF触发器的视图。
CREATE TRIGGER
仅当视图上的操作由行级INSTEAD OF触发器处理时,才会激发视图上的语句级触发器。如果操作由INSTEAD规则处理,则执行该规则发出的任何语句,以代替命名视图的原始语句,这样,将激发的触发器是在替换语句中命名的表上的触发器。同样,如果视图可自动更新,然后,通过自动将语句重写为视图基表上的操作来处理操作,以便基表的语句级触发器被触发。
感谢@Damien_The_Unbeliever识别此引用
我们可以在小提琴上演示这一点:https://www.db-fiddle.com/f/Ki2fBnAKC4rH1kMs66UaT/0
字符串
null
,但它对本演示并不重要。*| 前视计数器|代替视图计数器|柜台前|名称|
| --|--|--|--|
| 3 | 3 | 3 |汤姆|
如果您运行相同的测试,这次删除了INSTEAD OF触发器https://www.db-fiddle.com/f/jE6tbJAGTGRqpYKgXW346n/1,则只有表上的触发器会触发
| 前视计数器|代替视图计数器|柜台前|名称|
| --|--|--|--|
| 0 | 0 | 3 |
null
个|虽然这看起来像是一个奇怪的实现,但其背后的目的是针对只能在INSTEAD OF触发器中定义的复杂视图扩展对UPDATE/UPDATE/UPDATE的支持。子系统将在为每个ROW执行INSTEAD OF触发器之前 * 调用一次语句级别的BEFORE触发器。在操作结束时,将调用AFTER语句触发器。
其他RDBMS一般不支持视图上的触发器。这不是为了允许在任何任意视图上执行
BEFORE
/AFTER
,而是为了专门执行预处理。条件,这些条件可以阻止INSTEAD OF ROW语句的执行,而且因为ROW操作的顺序是不确定的,所以它允许扩展性站点帮助您审核或跟踪整个批处理,而不是尝试设计解决方案,尝试跟踪FOR EACH ROW内的第一行/最后一行之间的差异。