【问题标题】:How to do a trigger that modifies a record in a partitioned Postgres table?如何执行修改分区 Postgres 表中记录的触发器?
【发布时间】:2019-11-14 18:34:04
【问题描述】:

我有一个带有触发器的表,该触发器在记录更改时更新“已修改”时间戳。我用 BEFORE 触发器做到了:

CREATE OR REPLACE FUNCTION update_modified()
  RETURNS trigger AS
$$
BEGIN
  NEW.modified = now();
  RETURN NEW;
END;
$$
LANGUAGE plpgsql;

CREATE TRIGGER contact_update_modified
  BEFORE UPDATE
  ON contacts
  FOR EACH ROW
  EXECUTE PROCEDURE update_modified();

然后我对表进行了分区,当我尝试添加触发器时,我得到:

ERROR:  "contacts" is a partitioned table
DETAIL:  Partitioned tables cannot have BEFORE / FOR EACH ROW triggers.
SQL state: 42809

如果我将其更改为 AFTER 触发器,它不会更新修改后的字段(这是有道理的)。

如果我手动将触发器添加到每个子分区表,它似乎确实工作。我可以做到这一点,但这并不理想。有没有更好的办法?

【问题讨论】:

    标签: postgresql triggers partitioning database-trigger database-partitioning


    【解决方案1】:

    您使用的是哪种分区? 声明式还是使用继承

    如果您使用的是声明式,则不能使用 BEFORE INSERT/UPDATE ROW 触发器。 这不受支持,您可以在 documentation 中阅读:

    BEFORE ROW 触发器,如有必要,必须在单个分区上定义,而不是在分区表上。

    您可以在分区本身上创建此触发器。

    【讨论】:

      【解决方案2】:

      可以使用循环来完成。

      首先,如果您在迁移中使用,需要运行上述查询。

      SELECT child.relname
        FROM pg_inherits
                 JOIN pg_class parent            ON pg_inherits.inhparent = parent.oid
                 JOIN pg_class child             ON pg_inherits.inhrelid   = child.oid
        WHERE parent.relname='base_table_name';
      

      在获取结果并在每个循环中运行之后,就像这样。 这个例子在 ruby​​ on rails 中制作。

      ActiveRecord::Base.connection.execute(sql).each do |partion_name|
        sql = <<-SQL
        CREATE TRIGGER trigger_name_#{partion_name['relname']}
          BEFORE UPDATE 
          ON #{partion_name['relname']}
          FOR EACH ROW
        EXECUTE PROCEDURE function_name();
        SQL
        ActiveRecord::Base.connection.execute(sql)
      end
      

      但是您可以使用每个分区名称运行。 例如,你的表名是contacts,分区名是:contacts_0,contacts_1,就这样吧。

      CREATE TRIGGER contacts_0_update_modified
      BEFORE UPDATE
      ON contacts_0
      FOR EACH ROW
      EXECUTE PROCEDURE update_modified();
      
      CREATE TRIGGER contacts_1_update_modified
      BEFORE UPDATE
      ON contacts_1
      FOR EACH ROW
      EXECUTE PROCEDURE update_modified();
      

      【讨论】:

        猜你喜欢
        • 2012-04-11
        • 1970-01-01
        • 2020-07-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-07-31
        • 1970-01-01
        相关资源
        最近更新 更多