我有一个有很多列的表,其中一个是一lastUpdate
列。我正在 plpgsql 中为 Postgres 9.1 编写一个触发器,它应该lasUpdate
在对记录进行 UPDATE 时设置一个值。
挑战是从该触发器中排除一些预定义的列;意思是,更新那些特定的列不应该影响lastUpdate
记录的值。
有什么建议吗?
我有一个有很多列的表,其中一个是一lastUpdate
列。我正在 plpgsql 中为 Postgres 9.1 编写一个触发器,它应该lasUpdate
在对记录进行 UPDATE 时设置一个值。
挑战是从该触发器中排除一些预定义的列;意思是,更新那些特定的列不应该影响lastUpdate
记录的值。
有什么建议吗?
在 PostgreSQL 中,您可以使用 OLD 访问先前的值。和使用 NEW 的新的。别名。文档中甚至还有一个特定示例可以满足您的需求:
CREATE TRIGGER check_update
BEFORE UPDATE ON accounts
FOR EACH ROW
WHEN (OLD.balance IS DISTINCT FROM NEW.balance)
EXECUTE PROCEDURE check_account_update();
我知道这个问题太老了,但我发现自己也有同样的需求,我设法通过使用 information_schema.colmns 表的触发器来做到这一点。
我在这里附上可能的解决方案,其中唯一要编辑的参数是触发函数check_update_testtrig()中的TIMEUPDATE_FIELD和EXCLUDE_FIELDS:
CREATE TABLE testtrig
(
id bigserial NOT NULL,
col1 integer,
col2 integer,
col3 integer,
lastupdate timestamp not null default now(),
lastread timestamp,
CONSTRAINT testtrig_pkey PRIMARY KEY (id)
)
WITH (
OIDS=FALSE
);
CREATE OR REPLACE FUNCTION check_update_testtrig()
RETURNS trigger AS
$BODY$
DECLARE
TIMEUPDATE_FIELD text := 'lastupdate';
EXCLUDE_FIELDS text[] := ARRAY['lastread'];
PK_FIELD text := 'id';
ROW_RES RECORD;
IS_DISTINCT boolean := false;
COND_RES integer := 0;
BEGIN
FOR ROW_RES IN
SELECT column_name
FROM information_schema.columns
WHERE table_schema = TG_TABLE_SCHEMA
AND table_name = TG_TABLE_NAME
AND column_name != TIMEUPDATE_FIELD
AND NOT(column_name = ANY (EXCLUDE_FIELDS))
LOOP
EXECUTE 'SELECT CASE WHEN $1.' || ROW_RES.column_name || ' IS DISTINCT FROM $2.' || ROW_RES.column_name || ' THEN 1 ELSE 0 END'
INTO STRICT COND_RES
USING NEW, OLD;
IS_DISTINCT := IS_DISTINCT OR (COND_RES = 1);
END LOOP;
IF (IS_DISTINCT)
THEN
EXECUTE 'UPDATE ' || TG_TABLE_SCHEMA || '.' || TG_TABLE_NAME || ' SET ' || TIMEUPDATE_FIELD || ' = now() WHERE ' || PK_FIELD || ' = $1.' || PK_FIELD
USING NEW;
END IF;
RETURN NEW;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
CREATE TRIGGER trigger_update_testtrig
AFTER UPDATE
ON testtrig
FOR EACH ROW
EXECUTE PROCEDURE check_update_testtrig();
看着您的问题和您对 Jakub Kania 答案的评论,我会说解决方案的一部分是您将创建一个额外的表。
问题是对列的约束应该只应用列本身的功能,它不应该影响表中其他列的值。指定哪些列应该影响状态“lastUpdate”是 imo 业务逻辑。哪些列应该对状态列“lastUpdate”的值产生影响的想法随着业务的变化而变化,而不是表设计。因此,解决方案imo应该由一个表和一个触发器组成。
我会添加一个表,其中包含一个列列表(列可以是数组类型),可以在 Jakub Kania 所描述的表上的触发器中使用。如果默认行为应该是新列必须更改列“lastUpdate”的值,那么我会创建触发器,以便它只列出不更改“lastUpdate”值的列的名称。如果默认行为是不更改列“lastUpdate”的值,那么我建议您将该列的名称添加到列列表中,以防列表中的成员更改列“lastUpdate”的值'。
如果表列在列列表中,那么它是否应该更新字段 lastUpdate。