【问题标题】:Update a table with a trigger after update更新后使用触发器更新表
【发布时间】:2017-04-12 18:33:56
【问题描述】:

我有两张桌子

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

发生错误:

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

【问题讨论】:

    标签: postgresql triggers sql-update plpgsql postgresql-9.1


    【解决方案1】:

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

    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 data type。我的代码就是基于它构建的。

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

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

          AND    b.is_locked = FALSE;
      

    【讨论】:

    • 如何以及何时使用另一个触发器将 is_locked 列重置为 false?
    • @markmnl:这完全取决于您的用例的细节。您可能对咨询锁感兴趣。阅读herehere
    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

      在这种情况下无限递归,因为更新触发器将对表 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 布尔字段,该字段将在触发器执行时更新。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-11-03
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多