9

我正在研究一个简单的功能,它会自动更新表格中的某些内容。

create or replace function total() 
returns void as $$
declare
  sum int;
begin
  sum = (SELECT count(copy_id) FROM copies);
    update totalbooks
    set all_books = sum
    where num = 1;
  end;
$$ language plpgsql;

如果我执行“选择总计();” 它工作得很好,所以我做了一个函数触发器,以便它自动更新:

create or replace function total1() returns trigger as $$
begin
   perform (select total());
    return null;
end;
$$ language plpgsql;

但是在我执行这个之后:

create trigger total2
after update
on totalbooks
for each row
execute procedure total1();

它给了我一条错误消息:

ERROR:  stack depth limit exceeded
HINT:  Increase the configuration parameter "max_stack_depth" (currently 3072kB), after   ensuring the platform's stack depth limit is adequate.
CONTEXT:  SQL statement "SELECT (SELECT count(copy_id) FROM copies)"
PL/pgSQL function total() line 5 at assignment
SQL statement "SELECT (select total())"
PL/pgSQL function total1() line 3 at PERFORM
SQL statement "update totalbooks
set all_books = sum
where num = 1"
PL/pgSQL function total() line 6 at SQL statement
SQL statement "SELECT (select total())"
PL/pgSQL function total1() line 3 at PERFORM
SQL statement "update totalbooks
set all_books = sum
where num = 1"
PL/pgSQL function total() line 6 at SQL statement
SQL statement "SELECT (select total())"
PL/pgSQL function total1() line 3 at PERFORM
SQL statement "update totalbooks
set all_books = sum
where num = 1"
PL/pgSQL function total() line 6 at SQL statement
SQL statement "SELECT (select total())"
PL/pgSQL function total1() line 3 at PERFORM
SQL statement "update totalbooks
set all_books = sum
where num = 1"
PL/pgSQL function total() line 6 at SQL statement
SQL statement "SELECT (select total())"
PL/pgSQL function total1() line 3 at PERFORM
SQL statement "update totalbooks
set all_books = sum
where num = 1"
PL/pgSQL function total() line 6 at SQL statement
SQL statement "SELECT (select total())"
PL/pgSQL function total1() line 3 at PERFORM
SQL statement "update totalbooks
set all_books = sum
where num = 1"
PL/pgSQL function total() line 6 at SQL statement
SQL statement "SELECT (select total())"

显然我的触发器有问题。请帮忙。

我正在使用 Postgres 9.2.4,由 Visual C++ build 1600 编译,64 位

编辑:

我尝试了 pg_trigger_depth(),但现在触发器不会自动更新??我仍然需要执行'select total()'

这是我的新代码:

create or replace function total() 
returns void as $$
declare
  sum int;
begin
   sum = (SELECT count(copy_id) FROM copies);
    update totalbooks
    set all_books = sum;
end;
$$ language plpgsql;


create or replace function total1() returns trigger as $$
begin
  perform (select total());
  return null;
end;
$$ language plpgsql;

create trigger total2
after update
on totalbooks
for each row
WHEN (pg_trigger_depth()=0)
execute procedure total1();
4

3 回答 3

10

好的,如果您真的想要在更新时触发,您可以将这个触发器设置为特定于列的触发器,这样它就不会在更新到时触发all_books,这会导致您的递归。像这样的东西-

create trigger total2
after update of copy_id
on totalbooks
for each row
execute procedure total1();

当然,您可以更改触发该功能的列,我之所以选择copy_id是因为那是您要计算的。

然而

如果您正在更新count()结果,您只需将触发器INSERTDELETE操作放在一起。这样,触发器将在计数更改时触发,但本身不会被更新触发。// 编辑:由于您sum只是 中所有记录的计数copies,因此它只会在插入或更新记录时更改,因此在更新时运行此触发器无论如何都没有意义。

编辑:我认为添加指向CREATE TRIGGER Documentation的链接会很有用。请参阅标记为“事件”的部分,因为这详细说明了如何指定事件中的列。

编辑新信息:

鉴于听起来你需要完成什么,我认为你需要重新考虑你的数据设计,我建议你使用父子关系(任何时候你在一个表的许多行上缓存共享数据,因为它们有一些共同点,那表示您可能需要一个父表)。

有一个books表格,其中每一行是关于一本书的信息(标题、作者等),然后有一个copies表格,其中每一行包含关于一本书的副本的信息(序列号、最后一次签出等)。

这样,获取副本数就像SELECT COUNT(*) FROM copies WHERE book_id=[some book id].

如果您真的想在某处缓存计数,请在books桌子上进行。

创建一个INSERT OR UPDATE触发器copiesUPDATE books SET copy_count=(SELECT COUNT(*) FROM copies WHERE book_id=NEW.book_id) WHERE id=NEW.book_id

DELETE然后在副本上创建一个触发器UPDATE books SET copy_count=(SELECT COUNT(*) FROM copies WHERE book_id=OLD.book_id) WHERE id=OLD.book_id

两个触发器的原因是该NEW变量仅在INSERTUPDATE触发器中可用,并且OLD仅在DELETE触发器中可用。您可以将所有这些作为一个触发器来完成,但这需要的代码比我想放在这里的要多。

确保所有触发器都是AFTER触发器,否则计数中不会考虑新插入/删除的行。

于 2013-05-22T17:37:28.517 回答
0

Look into pg_trigger_depth:

http://www.postgresql.org/docs/9.2/static/functions-info.html

(9.2 or later)

于 2013-05-22T16:29:52.633 回答
0

在您的触发器内部:

IF pg_trigger_depth() < 2 THEN

  PERFORM total();

END IF;
于 2020-04-28T01:38:04.240 回答