我正在使用postgres。 假设我要创建以下触发器:
CREATE OR REPLACE FUNCTION auditlogfunc() RETURNS TRIGGER AS $example_table$
BEGIN
INSERT INTO AUDIT(EMP_ID, ENTRY_DATE) VALUES (new.ID, current_timestamp);
RETURN NEW;
END;
$example_table$ LANGUAGE plpgsql;
我想在许多表中使用此触发器,而不是每个表都有名为“id”的主键(表中根本没有'id'列)。 所以我需要以某种方式找出如何在我的触发器函数中使用主键,无论它具有哪个列名。 我怎样才能做到这一点?
答案 0 :(得分:1)
你的PostgreSQL版本是什么?您必须查询PostgreSQL目录才能实现您想要的目标。见下面的脚本:
我假设您的PostgreSQL支持JSONB
(9.4 +)。
CREATE TABLE public.test_table
(
id BIGINT NOT NULL,
a_column TEXT NOT NULL,
CONSTRAINT test_tablepkey PRIMARY KEY (id)
);
CREATE OR REPLACE FUNCTION auditlogfunc() RETURNS TRIGGER AS $example_table$
DECLARE
reg_id JSONB;
affected_row JSON;
BEGIN
IF TG_OP IN('INSERT', 'UPDATE') THEN
affected_row := row_to_json(NEW);
ELSE
affected_row := row_to_json(OLD);
END IF;
--Get PK columns
--You may want to extract this to a SQL function
WITH pk_columns (attname) AS (
SELECT
CAST(a.attname AS TEXT)
FROM
pg_index i
JOIN pg_attribute a ON a.attrelid = i.indrelid AND a.attnum = ANY(i.indkey)
WHERE
i.indrelid = TG_RELID
AND i.indisprimary
)
SELECT
json_object_agg(key, value) INTO reg_id
FROM
json_each_text(affected_row)
WHERE
key IN(SELECT attname FROM pk_columns);
--Raise collected PK
RAISE INFO 'PK: %', reg_id;
--TODO: your insert into audit table goes here
RETURN NEW;
END;
$example_table$ LANGUAGE plpgsql;
CREATE TRIGGER tg_audit_cadprodu_row AFTER INSERT OR UPDATE OR DELETE
ON public.test_table FOR EACH ROW EXECUTE PROCEDURE public.auditlogfunc();
--A simple test
INSERT INTO test_table VALUES (CAST((random() * 10000) AS INTEGER), 'Test');
答案 1 :(得分:0)
我拿了Michel Milezzi's answer并将其清理干净,因此它只返回我们需要的内容,并且在更简洁的语句中具有更好的性能。在Postgres v12.1上测试。我想它可以在9.4+上运行。
CREATE OR REPLACE FUNCTION auditlogfunc() RETURNS TRIGGER AS $example_table$
DECLARE
col TEXT = (
SELECT attname
FROM pg_index
JOIN pg_attribute ON
attrelid = indrelid
AND attnum = ANY(indkey)
WHERE indrelid = TG_RELID AND indisprimary
);
BEGIN
INSERT INTO AUDIT(EMP_ID, ENTRY_DATE) VALUES ((row_to_json(NEW) ->> col), current_timestamp);
RETURN NEW;
END;
$example_table$ LANGUAGE plpgsql;
首先,我要查询表的主键列的名称,并将其存储在col
变量中。我用特殊变量TG_RELID过滤查询,该变量是引起触发器的表的对象ID。 (请参见Postgres Docs。)
然后我们可以将其插入审核表中。我对这个问题所做的更改只是new.ID
。现在我们知道主键列的名称,可以将新行(将(或已经)插入,更新或删除的行)转换为json,然后使用{{1 }}变量。这对col
和BEFORE
触发器均适用。如果在AFTER
上触发,请将DELETE
更改为row_to_json(NEW)
。