3

我有两张桌子

 batch (batch_id,start_date,end_date,batch_strength,is_locked)
 sem (user_id,is_active,no_of_days)

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

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';

发生了错误:

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

4

3 回答 3

7

有几种方法可以防止您在触发器中构建的无限递归,最优雅和最高效的可能是在触发器函数WHERE的语句中添加子句:UPDATE

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();

我改变了一些其他的事情来走向理智:

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

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

  • 我还完全重写了您的UPDATE查询。特别是条件 onbatch.start_date以便可以使用索引(如果可用)。

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

        AND    b.is_locked = FALSE;
    
于 2013-02-10T08:55:27.707 回答
6

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

于 2013-01-03T13:30:03.930 回答
0

在这种情况下无限递归,因为更新触发器将对表进行更新操作,batch并且在触发器本身内部执行更新语句后也会触发相同的操作em_sem_batch。为了防止这种情况在表中添加一列,并且在触发器的更新语句中将该列更新为某个值和添加一个 if 条件来检查该列是否具有该常量值,如果是,则避免执行更新语句,否则执行更新语句。请参见下面的示例:

CREATE FUNCTION public.trigger_fuction()
    RETURNS trigger
    LANGUAGE 'plpgsql'
    NOT LEAKPROOF
AS $BODY$
BEGIN
  IF NEW.data_replicated=true THEN
    UPDATE sample SET data_replicated=false WHERE id=NEW.id;
    raise notice 'changed data replicated of sample with id as %',NEW.ID;
  END IF;
  RETURN NEW;
END;
$BODY$;


CREATE TRIGGER data_replication_trigger
  AFTER UPDATE
  ON sample
  FOR EACH ROW
  EXECUTE PROCEDURE trigger_fuction();

在此示例中,示例表具有 data_replicated 布尔字段,该字段将在执行触发器时更新。

于 2017-04-12T10:33:56.787 回答