【发布时间】:2020-04-23 10:13:26
【问题描述】:
我正在尝试为AFTER UPDATE 触发器编写一个 postgres 函数,该函数创建一个 JSON 对象,其中包含仅更改的列的列名及其更新值。我正在尝试创建一个可用于任何表的通用函数,因此使用 Record 作为函数参数。 old 和 new 来自触发器的 OLD 和 NEW 变量。最终目标是将返回的 JSON 保存到审计表中的 JSON 字段中。
CREATE OR REPLACE FUNCTION row_updates(old RECORD, new RECORD) RETURNS JSON AS
$$
DECLARE
updates JSON;
BEGIN
WITH columns AS (
SELECT json_object_keys(row_to_json(new)) "column"
)
SELECT
json_object_agg("column", new_value) INTO updates
FROM (
SELECT
"column",
(row_to_json(new)->"column" #>> '{}') as new_value,
(row_to_json(old)->"column" #>> '{}') as old_value
FROM
columns
) changes
WHERE
new_value IS DISTINCT FROM old_value;
RETURN updates;
END;
$$ LANGUAGE plpgsql;
CREATE OR REPLACE FUNCTION audit_change() RETURNS TRIGGER AS
$$
DECLARE
updates JSON;
BEGIN
IF (TG_OP = 'INSERT') THEN
raise NOTICE 'Logging insert on relation (%.%) %', TG_TABLE_SCHEMA, TG_TABLE_NAME;
RETURN NEW;
ELSIF (TG_OP = 'UPDATE') THEN
updates := row_updates(OLD, NEW)
raise NOTICE 'Logging update on relation (%.%) %', TG_TABLE_SCHEMA, TG_TABLE_NAME, updates;
RETURN NEW;
ELSIF (TG_OP = 'DELETE') THEN
raise NOTICE 'Logging delete on relation (%.%) %', TG_TABLE_SCHEMA, TG_TABLE_NAME;
RETURN OLD;
END IF;
END;
$$ LANGUAGE plpgsql;
我收到此错误:
ERROR: PL/pgSQL functions cannot accept type record.
有没有更好的方法来做到这一点?显然我想在非触发器函数中执行它,以便我可以在不同表的不同触发器中重用它。另外,如果可能的话,我可能希望将其用于AFTER INSERT 和AFTER DELETE 触发器,因此我不想在触发器函数中分支TG_OP 并重复上面SQL 中显示的逻辑。
最终目标:
=> select * from org_user;
id | org_id | user_id
----+--------+---------
1 | 1 | 1
23 | 1 | 3
=> update org_user set org_id=3, user_id = 4 where id = 23;
-- trigger creates following row in audit table
id | relation | record_id | updates
----+-----------+-----------+--------------
1 | org_user | 23 | {'org_id': 3, 'user_id': 4}
【问题讨论】:
标签: json postgresql plpgsql jsonb postgresql-9.5