You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何编写PostgreSQL触发器实现多表审计(含新旧值及表名)

PostgreSQL 统一审计表实现方案

1. 创建审计表

先按需求创建audit_details表,适配字段类型以兼容多场景:

CREATE TABLE audit_details (
    date_time TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
    table_name TEXT NOT NULL,
    old_data JSONB,
    new_data JSONB,
    "user" TEXT NOT NULL DEFAULT CURRENT_USER,
    primary_key_of_table TEXT NOT NULL
);

说明:采用JSONB而非JSON,支持索引与高效查询;date_time带时区保证时间准确性;primary_key_of_table存文本格式,兼容不同表的主键类型(整数、UUID等)。

2. 编写通用触发器函数

这个函数可自动适配不同表结构,动态提取审计所需信息:

CREATE OR REPLACE FUNCTION audit_trigger_function()
RETURNS TRIGGER AS $$
DECLARE
    pk_columns TEXT[];
    pk_value TEXT;
BEGIN
    -- 动态获取当前表的主键列名
    SELECT ARRAY_AGG(attname)
    INTO pk_columns
    FROM pg_constraint con
    JOIN pg_attribute att ON att.attrelid = con.conrelid AND att.attnum = ANY(con.conkey)
    WHERE con.contype = 'p' AND con.conrelid = TG_RELID;

    -- 根据操作类型提取主键值
    IF TG_OP = 'DELETE' THEN
        SELECT string_agg((row_to_json(OLD)->>col)::TEXT, ', ')
        INTO pk_value
        FROM unnest(pk_columns) col;
    ELSE
        SELECT string_agg((row_to_json(NEW)->>col)::TEXT, ', ')
        INTO pk_value
        FROM unnest(pk_columns) col;
    END IF;

    -- 插入审计记录
    INSERT INTO audit_details (table_name, old_data, new_data, primary_key_of_table)
    VALUES (
        TG_TABLE_NAME,
        CASE WHEN TG_OP IN ('UPDATE', 'DELETE') THEN row_to_json(OLD)::JSONB ELSE NULL END,
        CASE WHEN TG_OP IN ('INSERT', 'UPDATE') THEN row_to_json(NEW)::JSONB ELSE NULL END,
        pk_value
    );

    RETURN NULL; -- 返回NULL不影响原表操作逻辑
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;

说明:

  • TG_RELID是触发器关联表的OID,用于动态查询主键;
  • TG_TABLE_NAME直接获取触发操作的表名;
  • SECURITY DEFINER确保触发器以创建者权限执行,避免跨用户操作的权限问题;
  • 按操作类型(INSERT/UPDATE/DELETE)分别赋值old_data和new_data,避免无效数据写入。

3. 为目标表绑定触发器

假设你的5张表为table_a、table_b、table_c、table_d、table_e,为每张表创建触发器:

-- 为table_a创建审计触发器
CREATE TRIGGER audit_table_a
AFTER INSERT OR UPDATE OR DELETE ON table_a
FOR EACH ROW EXECUTE FUNCTION audit_trigger_function();

-- 为table_b创建审计触发器
CREATE TRIGGER audit_table_b
AFTER INSERT OR UPDATE OR DELETE ON table_b
FOR EACH ROW EXECUTE FUNCTION audit_trigger_function();

-- 重复上述逻辑,为table_c/table_d/table_e创建触发器

4. 验证效果

执行表操作后,查询审计表查看结果:

SELECT * FROM audit_details ORDER BY date_time DESC;

示例返回结果

date_timetable_nameold_datanew_datauserprimary_key_of_table
2024-05-20 14:30:00table_aNULL{"id": 1, "name": "test", "age": 25}admin1
2024-05-20 14:31:00table_a{"id": 1, "name": "test", "age": 25}{"id": 1, "name": "updated", "age": 26}admin1
2024-05-20 14:32:00table_b{"uuid": "abc123", "value": "foo"}NULLuser1abc123

内容的提问来源于stack exchange,提问作者Ranjit Chavan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 12:40:34