更新后使用触发器更新表

use*_*539 2 postgresql triggers plpgsql sql-update postgresql-9.1

我有两张桌子

 batch (batch_id,start_date,end_date,batch_strength,is_locked)
 sem (user_id,is_active,no_of_days)
Run Code Online (Sandbox Code Playgroud)

我已经执行了下面给出的触发器过程,然后使用查询更新表

CREATE OR REPLACE FUNCTION em_batch_update()
  RETURNS trigger AS $em_sem_batch$
BEGIN

UPDATE batch set is_locked='TRUE'
where (start_date
       + (select no_of_days from sem
          WHERE is_active='TRUE' and user_id='OSEM')
      ) <= current_date;

return NEW;

END;
$em_sem_batch$  LANGUAGE plpgsql;

CREATE TRIGGER em_sem_batch
BEFORE UPDATE ON batch FOR EACH ROW EXECUTE PROCEDURE em_batch_update();

update em_batch set batch_strength=20 where batch_id='OD001C001B3';
Run Code Online (Sandbox Code Playgroud)

发生了错误:

错误:超出堆栈深度限制
提示:确保平台的堆栈深度限制足够后,增加配置参数"max_stack_depth"(当前为2048kB).

Erw*_*ter 7

有几种方法可以防止内置到触发器中的无限递归,最优雅和高性能的可能是在触发器函数中WHEREUPDATE语句添加一个子句:

CREATE OR REPLACE FUNCTION em_batch_update()
  RETURNS trigger AS
$func$
BEGIN

UPDATE batch b
SET    is_locked = TRUE
FROM   sem s
WHERE  s.is_active
AND    s.user_id = 'OSEM'
AND    b.start_date <= (current_date - s.no_of_days)
AND    b.is_locked IS DISTINCT FROM TRUE; -- prevent infinite recursion!

RETURN NULL;

END
$func$  LANGUAGE plpgsql;

CREATE TRIGGER em_sem_batch
BEFORE UPDATE ON batch
FOR EACH STATEMENT
EXECUTE PROCEDURE em_batch_update();
Run Code Online (Sandbox Code Playgroud)

我改变了一些其他的东西来走向理智:

每个语句触发器调用的触发器函数应始终返回NULL.

  • batch.is_lockedsem.is_active看起来像布尔列.为它们使用适当的boolean数据类型.我的代码正在构建它.

  • 我也UPDATE完全重写了你的查询.特别是条件,batch.start_date以便可以使用索引.

  • 如果batch.is_locked已定义NOT NULL,则WHERE条件可简化为:

        AND    b.is_locked = FALSE;
    
    Run Code Online (Sandbox Code Playgroud)


Pet*_*aut 5

您的UPDATE触发器UPDATE在同一表上运行另一个触发器,它将再次触发该触发器,因此您将获得无限递归。您可能需要重新设计一下,但是如果不解释您要尝试做的事情,很难说怎么做。