在 PostgreSQL 中的视图上执行触发器

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

我对数据库触发器和/或视图不太熟悉。我目前正在使用 PostgreSQL 和 HSQL,尽管数据库并不是太重要。我只是想知道任何数据库是否提供这样的东西:

我有一个像这样的(示例)表:

CREATE TABLE DUMMY_TABLE (ID INTEGER, NUMBER INTEGER);

我创建了一个这样的视图:

CREATE VIEW DUMMY_VIEW AS SELECT * FROM DUMMY_TABLE WHERE NUMBER > 5;

我插入了几个实体:

INSERT INTO DUMMY_TABLE VALUES(1,2);
INSERT INTO DUMMY_TABLE VALUES(1,10);

所以当然,当我打电话时,

DUMMY_VIEW
只包含
VALUES(1,10)

SELECT * FROM DUMMY_VIEW;

所以现在我想做的是向

DUMMY_VIEW
添加一个触发器,每当插入具有
NUMBER > 5
的实体时就会调用该触发器。

我尝试过将触发器直接添加到 HSQL 和 PostgreSQL 中的

DUMMY_VIEW
,但他们说触发器不能添加到视图中。

这(或功能类似的解决方案)可能吗?

database postgresql view triggers hsqldb
7个回答
18
投票

需要注意的是,PostgreSQL 9.1+ 支持视图上的触发器。请参阅等待 9.1 – 视图上的触发 对此进行简要介绍。


9
投票

是的,触发器不能直接放置在视图上。您应该做的是在基表上放置一个触发器并检查新的 NUMBER 行的值是否大于 5。

注意:视图只是一个存储的选择语句,因此它并不真正保存数据。这就是为什么人们无法检查视图结构中是否正在插入、删除或更新数据。


2
投票

我认为你必须将触发器放在桌子上,而不是视图上。

触发器可以在视图上使用查询,以便您DRY

还有其他原因需要触发器位于视图而不是表上吗?

回复评论的示例

-- Create function
CREATE FUNCTION doWhatIwant() RETURNS trigger AS '
BEGIN
IF NEW.number > 5 THEN
  do_stuff
END IF;
RETURN NEW;
END;
' LANGUAGE plpgsql;

-- Create trigger
CREATE TRIGGER yourTrigger AFTER INSERT ON dummy_table
  FOR EACH ROW EXECUTE PROCEDURE doWhatIwant();

1
投票

我不确定你想达到什么目的。

触发器在数据更改时执行代码。视图是(比方说)“可调用的数据子集”。它实际上是不存在的,除非你从中选择。它不能包含触发器,因为它不包含任何内容。

所以基本上你需要在基表上有一个触发器。


1
投票

如果您将触发器添加到与视图具有相同条件的表中,这是可能的。

扳机主体应具有类似以下内容:

if (inserted.NUMBER > 5) {
   do something;
}
//do nothing if inserted.NUMBER is not > 5

1
投票

HSQLDB 2.x 同时支持可更新视图和触发可更新视图。

您的视图示例可以自行更新。因此,您可以使用视图而不是表来插入/删除/更新行。这将不允许包含 NUMBER <= 5 in inserts and updates.

的行

您还可以在视图上定义触发器。这些触发器是用 INSTEAD OF INSERT、INSTEAD OF UPDATE 或 INSTEAD OF DELETE 定义的。在触发器的主体中,您可以检查值并引发无效输入的异常,或将行插入基表中。

参见 http://hsqldb.org/doc/2.0/guide/triggers-chapt.html


0
投票

例如,您创建

person
表,然后向其中插入 2 行,如下所示。 *我的帖子解释了一个触发器(带有视图):

CREATE TABLE person (
  id INTEGER,
  name VARCHAR(20)
);

INSERT INTO person (id, name) 
VALUES (1, 'John'), (2, 'David');

接下来,创建

log
表,然后将
num
0
的行插入到
log
表中,如下所示:

CREATE TABLE log (
  num INTEGER
);

INSERT INTO log (num) VALUES (0);

现在,您可以使用

my_func()
RETURNS trigger
创建
LANGUAGE plpgsql
触发函数,使
num
递增 1,如下所示:

CREATE FUNCTION my_func() RETURNS trigger
AS $$
BEGIN
  UPDATE log SET num = num + 1;
  RETURN NULL;
END;
$$ LANGUAGE plpgsql;

接下来,您创建

my_v
视图,如下所示。 *我的帖子详细解释了一个视图:

CREATE VIEW my_v AS
  SELECT * FROM person;

现在,您可以创建

my_t
触发器,当每行的
my_func()
上阻止
UPDATE
DELETE
操作时,运行
my_view
,如下所示:

CREATE TRIGGER my_t INSTEAD OF UPDATE OR DELETE ON my_v
FOR EACH ROW EXECUTE FUNCTION my_func();

*备注:

  • INSTEAD OF
    可以阻止操作。

  • 您可以将

    INSTEAD OF
    与视图和
    FOR EACH ROW
    一起使用,但不能与函数和
    FOR EACH STATEMENT
    一起使用,否则会出现错误。

  • 使用

    UPDATE OF
    时不能用
    INSTEAD OF
    指定一列或多列,否则会出错。

  • 视图上带有

    BEFORE
    AFTER
    以及
    INSERT
    UPDATE
    DELETE
    的触发器不起作用。 *我的问题和答案详细解释了。

然后,用

person
my_v
表插入一行,则
num
仍然是
0
,如下所示:

postgres=# INSERT INTO my_v (id, name) VALUES (3, 'Robert');
INSERT 0 1
postgres=# SELECT * FROM person;
 id |  name
----+--------
  1 | John
  2 | David
  3 | Robert
(3 rows)

postgres=# SELECT num FROM log;
 num
-----
   0
(1 row)

然后,您尝试使用

name
Tom
表上所有 3 行的
person
更新为
my_v
,然后更新被阻止,然后
num
变为
3
,如下所示:

postgres=# UPDATE my_v SET name = 'Tom';
UPDATE 0
postgres=# SELECT * FROM person;
 id |  name
----+--------
  1 | John
  2 | David
  3 | Robert
(3 rows)

postgres=# SELECT num FROM log;
 num
-----
   3
(1 row)

然后,您尝试从

person
表中删除 2 行,其中
id
2
3
my_v
,则删除被阻止,然后
num
5
,如下所示:

postgres=# DELETE FROM my_v WHERE id IN (2, 3);
DELETE 0
postgres=# SELECT * FROM person;
 id |  name
----+--------
  1 | John
  2 | David
  3 | Robert
(3 rows)

postgres=# SELECT num FROM log;
 num
-----
   5
(1 row)
© www.soinside.com 2019 - 2024. All rights reserved.