视图上带有“BEFORE”或“AFTER”以及“INSERT”、“UPDATE”或“DELETE”的触发器在 PostgreSQL 中不起作用

问题描述 投票:0回答:1

我创建的,如下图:

  • 一个
    table
    称为
    person
  • 一个
    table
    称为
    log
    ,其中插入了 1 行。
  • 一个
    view
    称为
    my_v
  • 一个
    trigger function
    称为
    my_func()
    ,其目的是将
    num.log
    增加
    1
  • 一个名为
    trigger
    my_t
    ,在
    my_func()
    上执行
    before
    each statement
    INSERT
    UPDATE
    DELETE
    my_v
    )。
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();

通过此设置,表

num 
log
的值预计将计算触发器调用
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_func()
上发生
INSERT
UPDATE
DELETE
操作之前或之后触发
my_v

sql database postgresql sql-view postgresql-triggers
1个回答
0
投票

PostgreSQL 上的行级触发器不支持 BeforeAfter

39.1。触发器行为概述
行级 BEFORE 触发器在对特定行进行操作之前立即触发,而行级 AFTER 触发器在语句末尾(但在任何语句级 AFTER 触发器之前)触发。 这些类型的触发器只能在外部表上定义,不能在视图上定义。

INSTEAD OF 触发器只能在视图上定义,并且只能在行级别;当视图中的每一行被识别为需要操作时,它们会立即触发。

事实上 INSTEAD OF 触发器只能在视图上定义。

要么在底层table上设置before触发器,要么使用INSTEAD OF触发器并将逻辑放入其中and,然后对底层表执行操作。

© www.soinside.com 2019 - 2024. All rights reserved.