【问题标题】:How to log data change in postgresql?如何在 postgresql 中记录数据更改?
【发布时间】:2012-11-26 23:24:28
【问题描述】:

此问题可能与与此主题相关的其他一些问题可能重复。我发现了一些类似的问题(几年前有人问过一些问题,关于这个话题的讨论似乎几乎结束了)。但是我的问题没有找到可行的解决方案。我有一个包含大量表的数据库,其中包含大量数据。我需要记录存储在特定数据库表中的数据发生的每一个变化。

例如,我有一个用于存储员工详细信息的表。

id    employeename
 1    ab

而且,这个数据变成了

id    employeename
 1    cd

所以我需要记录这些数据。

即员工姓名

ab

改为

光盘

在员工详细信息表中

每次更改存储在表中的内容时,我都需要记录数据。真的有可能吗?如果是这样,我该怎么做?其中涉及哪些步骤?在这种情况下,我非常担心日志文件的大小。在这种情况下,有什么好的选择?我正在使用postgresql8.4。任何好的建议都会对我有很大帮助。提前致谢。

【问题讨论】:

标签: postgresql postgresql-8.4 audit-trail


【解决方案1】:

非常通用的触发函数,在那里找到:https://www.cybertec-postgresql.com/en/tracking-changes-in-postgresql/

存储历史的表:

CREATE SCHEMA logging;
CREATE TABLE logging.t_history (
        id             serial,
        tstamp         timestamp DEFAULT now(),
        schemaname     text,
        tabname        text,
        operation      text,
        who            text DEFAULT current_user,
        new_val        json,
        old_val        json
);

触发器:

CREATE FUNCTION change_trigger() RETURNS trigger AS $$
       BEGIN
         IF TG_OP = 'INSERT'
         THEN INSERT INTO logging.t_history (
                tabname, schemaname, operation, new_val
              ) VALUES (
                TG_RELNAME, TG_TABLE_SCHEMA, TG_OP, row_to_json(NEW)
              );
           RETURN NEW;
         ELSIF  TG_OP = 'UPDATE'
         THEN
           INSERT INTO logging.t_history (
             tabname, schemaname, operation, new_val, old_val
           )
           VALUES (TG_RELNAME, TG_TABLE_SCHEMA, TG_OP, row_to_json(NEW), row_to_json(OLD));
           RETURN NEW;
         ELSIF TG_OP = 'DELETE'
         THEN
           INSERT INTO logging.t_history
             (tabname, schemaname, operation, old_val)
             VALUES (
               TG_RELNAME, TG_TABLE_SCHEMA, TG_OP, row_to_json(OLD)
             );
             RETURN OLD;
         END IF;
       END;
$$ LANGUAGE 'plpgsql' SECURITY DEFINER;

应用触发器:

CREATE TRIGGER t BEFORE INSERT OR UPDATE OR DELETE ON your_table
        FOR EACH ROW EXECUTE PROCEDURE change_trigger();

【讨论】:

  • 谢谢。我根据自己的需要对其进行了调整,并且效果很好。我发现当函数是 SECURITY DEFINER 时,我需要保存 session_user 而不是 current_user,因为后者是函数的所有者,而不是连接的用户。
  • 如果是 upsert,比如说INSERT INTO t (x, y) VALUES (x, y) ON CONFLICT (x) DO UPDATE SET y = EXCLUDED.y; 2 行写入表logging.t_historyBEFORE。如果我没有忽略任何问题,使用 AFTER 似乎是一个可能的解决方案。
  • 跟进之前的评论:我没有看到这个问题:How can I use a PostgreSQL triggers to store changes (SQL statements and row changes),其中提出了使用AFTER的类似解决方案。
【解决方案2】:

这是一个触发器示例,而不是记录此类更改:Audit trigger

【讨论】:

  • 这是一个很好的答案。但是,如果我想监控 100 多个表中的数据,我该怎么做呢?
  • @harry 只需创建 100 多个触发器。 (您不需要重新创建函数和表。只需CREATE TRIGGER tab100_if_modified_trg AFTER INSERT OR UPDATE OR DELETE ON tab100 FOR EACH ROW EXECUTE PROCEDURE audit.if_modified_func();
  • 或者,如果您想在所有表上创建触发器,请使用pg_class table 获取表名和一些动态 SQL 来创建所有触发器。
猜你喜欢
  • 1970-01-01
  • 2017-04-23
  • 1970-01-01
  • 2012-07-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-11
相关资源
最近更新 更多