【问题标题】:record "new" is not assigned yet记录“新”尚未分配
【发布时间】:2020-01-21 00:44:59
【问题描述】:

我正在尝试实现表分区,并且我在 PostgreSQL 中有以下代码(来自https://www.postgresql.org/docs/9.6/ddl-partitioning.html

CREATE or replace FUNCTION child_tables.func_inventory_movement_insert_trigger()
    RETURNS trigger 
    LANGUAGE 'plpgsql'
    COST 100
    VOLATILE NOT LEAKPROOF
AS $BODY$BEGIN

   IF  ( NEW.report_date >=  '2019-04-01 ' AND
         NEW.report_date <  '2019-05-01 ' ) THEN
        INSERT INTO child_tables.inventory_movement_y2019m03 VALUES (NEW.*);

    ELSIF ( NEW.report_date >=  '2019-06-01 ' AND
            NEW.report_date <  '2019-07-01 ' ) THEN

        INSERT INTO child_tables.inventory_movement_y2019m04 VALUES (NEW.*);

    ELSE
        RAISE EXCEPTION 
        ' out of range exception.  Fix the child_tables.func_inventory_movement_insert_trigger() function. ';
    END IF;
    RETURN NULL;
END;
$BODY$;

触发功能:

CREATE TRIGGER im_partition_trigger
BEFORE INSERT OR DELETE OR UPDATE 
ON core.inventory_movement
FOR EACH ROW
EXECUTE PROCEDURE child_tables.func_inventory_movement_insert_trigger();

在上述触发器之后或之前都尝试过。

ERROR: record "new" is not assigned yet
DETAIL: The tuple structure of a not-yet-assigned record is indeterminate.

仅供参考,相同的代码适用于另一个表。

有什么建议吗?

【问题讨论】:

  • 你的错误是什么时候出现的?在CREATE TRIGGER 或触发触发器时?如果开火,在哪种类型的事件上?我觉得问题是NEWDELETE 结合使用。
  • 嗨,当我触发触发器时,现在它是插入事件
  • 请添加此信息和触发触发器的命令。您说相同的代码正在另一张桌子上工作。触发器是否用于相同的事件,您是否触发相同的事件?
  • 是的,两者都是相同的事件。我有一个存储过程,我将调用该过程,它将从其他阶段表中提取数据,然后将其插入到我的核心表中。所以在插入这个表之前触发器会自动触发。

标签: postgresql function triggers plpgsql table-partitioning


【解决方案1】:

您的触发器已定义

BEFORE INSERT OR DELETE OR UPDATE 

但是 NEW 没有为 DELETE 定义。所以你的触发函数肯定会像以前那样失败。

INSERT/UPDATE/DELETE编写单独的触发函数和触发器(推荐)。显示的触发函数只处理INSERT。所以这个触发器是有意义的:

CREATE TRIGGER im_partition_trigger
BEFORE INSERT    -- !!
ON core.inventory_movement
FOR EACH ROW EXECUTE PROCEDURE child_tables.func_inventory_movement_insert_trigger();

或者将所有对OLDNEW 的调用嵌套在IFCASE 构造中的组合触发器函数中,检查TG_OP

Code examples in many related questions.

也就是说,要实现表分区,我更愿意在 Postgres 10 或更高版本中使用 declarative partitioning。理想情况下,使用即将推出的 Postgres 12,它为分区带来了很大的改进。

除此之外,在 Postgres 11 或更高版本中,不如使用触发器的固定语法:

...
FOR EACH ROW EXECUTE FUNCTION child_tables.func_inventory_movement_insert_trigger();

这是一个函数,而不是“过程”。

【讨论】:

  • 但是,这里相同的触发器正在为另一个表工作。正如我所提到的,在存储过程中插入/更新将执行。由于某些应用程序依赖关系,目前我们使用的是 9.6v。
  • NEW 是为 INSERTUPDATE 定义的,但不是为 DELETE 定义的。顺便说一句,“函数”,而不是“存储过程”。
  • 感谢您分享您的想法,我通过一些试验和错误发现并成功使用以下语法,CREATE TRIGGER im_partition_trigger_before BEFORE INSERT OR DELETE OR UPDATE OF coulmn1,coulmn2,column3 ON core.inventory_movement FOR EACH ROW EXECUTE PROCEDURE child_tables.func_inventory_movement_insert_trigger();,在 9.6 中我们必须使用 PROCEDURE 而不是 FUNCTION
  • 这仍然是危险的错误。给定的函数将在第一个 DELETE 事件中出错。是的,您必须在 pg 9.6 中使用关键字PROCEDURE。它仍然是关于一个函数。因此第 11 页中的语法发生了变化。
  • 嗨@ErwinBrandstetter,令我惊讶的是,经过几次尝试,相同的触发器功能仍在工作。可能是一个错误,或者我不确定。 CREATE TRIGGER im_partition_trigger_before_i_u_d before INSERT OR UPDATE or delete ON core.inventory_movement FOR EACH ROW EXECUTE PROCEDURE child_tables.func_inventory_movement_insert_trigger();
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-08-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多