【问题标题】:Postgresql trigger which execute update query only one time for statemntPostgresql 触发器,仅对语句执行一次更新查询
【发布时间】:2020-06-09 08:07:36
【问题描述】:

当我需要使用触发器时,我使用 PostgreSQL 11.8 并面临任务。主要目标 - 当从表产品中设置或更新某些行时,在执行 UPDATE 或 INXERT 之后,我需要为表 products 中所有存在的行设置 created_at 数据,该表具有相同的 group_identity。我创建了这个触发器。

CREATE OR REPLACE FUNCTION maint_sales_summary_bytime() RETURNS TRIGGER
AS $maint_sales_summary_bytime$
    DECLARE
        delta_time_key          timestamp;
        delta_group_identity   varchar;

    BEGIN



        IF (TG_OP = 'UPDATE') THEN

            delta_time_key = NEW.created_at;
            delta_group_identity = NEW.group_identity;

        ELSIF (TG_OP = 'INSERT') THEN

            delta_time_key = NEW.created_at;
            delta_group_identity = NEW.group_identity;

        END IF;

                UPDATE products
                SET 
                created_at = delta_time_key
                WHERE group_identity = delta_group_identity;    

        RETURN NULL;

    END;
$maint_sales_summary_bytime$ LANGUAGE plpgsql;

CREATE TRIGGER maint_sales_summary_bytime
AFTER INSERT OR UPDATE ON products
    FOR EACH ROW EXECUTE PROCEDURE maint_sales_summary_bytime();

但是当我尝试执行它时

UPDATE products
SET name = 'hello test1'
WHERE id = 131545

我面临 78 秒的花费时间和错误

UPDATE products
    SET name = 'hello test1'
    WHERE id = 131545
> ERROR:  stack depth limit exceeded
  HINT:  Increase the configuration parameter "max_stack_depth" (currently 2048kB), after ensuring the platform's stack depth limit is adequate.
  CONTEXT:  SQL statement "SELECT 1 FROM ONLY "public"."brand" x WHERE "id" OPERATOR(pg_catalog.=) $1 FOR KEY SHARE OF x"
  SQL statement "UPDATE products
                  SET 
                                    created_at = delta_time_key
                  WHERE group_identity = delta_group_identity"
  PL/pgSQL function maint_sales_summary_bytime() line 23 at SQL statement
  SQL statement "UPDATE products
                  SET 
                                    created_at = delta_time_key
                  WHERE group_identity = delta_group_identity"
  PL/pgSQL function maint_sales_summary_bytime() line 23 at SQL statement
  SQL statement "UPDATE products
                  SET 
                                    created_at = delta_time_key
                  WHERE group_identity = delta_group_identity"
  PL/pgSQL function maint_sales_summary_bytime() line 23 at SQL statement
  SQL statement "UPDATE products
                  SET 
                                    created_at = delta_time_key
                  WHERE group_identity = delta_group_identity"
  PL/pgSQL function maint_sales_summary_bytime() line 23 at SQL statement
  SQL statement "UPDATE products
                  SET 
                                    created_at = delta_time_key
                  WHERE group_identity = delta_group_identity"
  PL/pgSQL function maint_sales_summary_bytime() line 23 at SQL statement
  SQL statement "UPDATE products
                  SET 
                                    created_at = delta_time_key
                  WHERE group_identity = delta_group_identity"
  PL/pgSQL function maint_sales_summary_bytime() line 23 at SQL statement
  SQL statement "UPDATE products
                  SET 
                                    created_at = delta_time_key
                  WHERE group_identity = delta_group_identity"
  PL/pgSQL function maint_sales_summary_bytime() line 23 at SQL statement
  SQL statement "UPDATE products
                  SET 
                                    created_at = delta_time_key
                  WHERE group_identity = delta_group_identity"
  PL/pgSQL function maint_sales_summary_bytime() line 23 at SQL statement
  SQL statement "UPDATE products
                  SET 
                                    created_at = delta_time_key
                  WHERE group_identity = delta_group_identity"
  PL/pgSQL function maint_sales_summary_bytime() line 23 at SQL statement
  SQL statement "UPDATE products
                  SET 
                                    created_at = delta_time_key
                  WHERE group_identity = delta_group_identity"
  PL/pgSQL function maint_sales_summary_bytime() line 23 at SQL statement
  SQL statement "UPDATE products
                  SET 
                                    created_at = delta_time_key
                  WHERE group_identity = delta_group_identity"
  PL/pgSQL function maint_sales_summary_bytime() line 23 at SQL statement
  SQL statement "UPDATE products
                  SET 
                                    created_at = delta_time_key
                  WHERE group_identity = delta_group_identity"
  PL/pgSQL function maint_sales_summary_bytime() line 23 at SQL statement
  SQL statement "UPDATE products
                  SET 
                                    created_at = delta_time_key
                  WHERE group_identity = delta_group_identity"
  PL/pgSQL function maint_sales_summary_bytime() line 23 at SQL statement
  SQL statement "UPDATE products
                  SET 
                                    created_at = delta_time_key
                  WHERE group_identity = delta_group_identity"
  PL/pgSQL function maint_sales_summary_bytime() line 23 at SQL statement
  SQL statement "UPDATE products
                  SET 
                                    created_at = delta_time_key
                  WHERE group_identity = delta_group_identity"
  PL/pgSQL function maint_sales_summary_bytime() line 23 at SQL statement
  SQL statement "UPDATE products
                  SET 
                                    created_at = delta_time_key
                  WHERE group_identity = delta_group_identity"
  PL/pgSQL function main
> Time: 86.868s

看起来像触发器尝试对来自products 的每一行执行此查询,但我只需要在语句 INSERT 或 UPDATE 执行 ro ONE 行后执行此触发器一次

【问题讨论】:

  • 不相关,但是:开头的IF 语句似乎没用,因为两个分支都做同样的事情。无论如何也不需要变量,因为您也可以参考 UPDATE 语句中的new 记录

标签: postgresql


【解决方案1】:

您的触发器是递归触发器。

您可以尝试使用以下方法禁用递归:

CREATE TRIGGER maint_sales_summary_bytime
AFTER INSERT OR UPDATE ON products
FOR EACH ROW 
WHEN (pg_trigger_depth() = 0)
EXECUTE PROCEDURE maint_sales_summary_bytime();

pg_trigger_depth()

【讨论】:

  • CREATE TRIGGER maint_sales_summary_bytime AFTER INSERT OR UPDATE ON products WHEN (pg_trigger_depth() = 0) FOR EACH ROW EXECUTE PROCEDURE maint_sales_summary_bytime(); 我遇到了) > ERROR: syntax error at or near "FOR" LINE 4: FOR EACH ROW EXECUTE PROCEDURE maint_sales_summary_bytim..
  • CREATE TRIGGER maint_sales_summary_bytime AFTER INSERT OR UPDATE ON products FOR EACH ROW WHEN (pg_trigger_depth() = 0) EXECUTE PROCEDURE maint_sales_summary_bytime(); 很有魅力,谢谢
  • 好的,我已经确定了答案。
最近更新 更多