PostgreSQL-确定更新了哪些列

PostgreSQL-确定更新了哪些列,postgresql,triggers,plpgsql,Postgresql,Triggers,Plpgsql,我有一个包含许多列的表,其中一列是lastUpdate列。 我正在为Postgres 9.1编写一个plpgsql触发器,它应该在更新记录时为lasUpdate设置一个值 挑战在于从触发器中排除一些预定义的列;也就是说,更新这些特定列不应该影响记录的lastUpdate值 有什么建议吗?在PostgreSQL中,您可以使用OLD访问以前的值。新的使用新的。别名。中甚至有一个具体的例子来说明您的需要: CREATE TRIGGER check_update BEFORE UPDATE ON acc

我有一个包含许多列的表,其中一列是
lastUpdate
列。 我正在为Postgres 9.1编写一个plpgsql触发器,它应该在更新记录时为
lasUpdate
设置一个值

挑战在于从触发器中排除一些预定义的列;也就是说,更新这些特定列不应该影响记录的
lastUpdate


有什么建议吗?

在PostgreSQL中,您可以使用OLD访问以前的值。新的使用新的。别名。中甚至有一个具体的例子来说明您的需要:

CREATE TRIGGER check_update
BEFORE UPDATE ON accounts
FOR EACH ROW
WHEN (OLD.balance IS DISTINCT FROM NEW.balance)
EXECUTE PROCEDURE check_account_update();

看看您的问题和您对Jakub Kania答案的评论,我想说解决方案的一部分是您将创建一个额外的表

问题在于,对列的约束只应应用于列本身的功能,而不应影响表中其他列的值。指定哪些列应影响状态“lastUpdate”是imo业务逻辑。 哪些列应该对状态列“lastUpdate”的值产生影响的想法随着业务而变化,而不是表设计。因此,imo解决方案应包括一个表和一个触发器

我将添加一个表,其中包含一列,用于列列表(列可以是数组类型),可以在表上的触发器中使用,如Jakub Kania所述。如果默认行为是新列必须更改列“lastUpdate”的值,那么我会创建触发器,以便它只列出不更改“lastUpdate”值的列的名称。如果默认行为是不更改列“lastUpdate”的值,那么我建议您将列的名称添加到列列表中,以防列表中的成员更改列“lastUpdate”的值


如果表列在列列表中,则应更新字段lastUpdate

我知道这是一个太老的问题,但我发现自己也有同样的需要,于是我使用information_schema.colmns表通过触发器成功地解决了这个问题

我在此附上一个可能的解决方案,其中唯一要编辑的参数是触发器函数检查更新测试触发器()中的时间更新字段和排除字段:

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();

我不想静态地键入所有“影响latUpdate”列并比较它们的新/旧数据。添加的新列的默认行为应该是影响lastUpdate。如果我决定将其添加到排除列表中,我会将其添加到触发器中。听起来合理吗?@Rizon虽然这样的功能很好,但目前还没有。@Rizon,您可以使用其他语言,如PL/Perl。您的问题还不清楚。1.)更新可以包括多列。那么影响这两种列的更新又如何呢?2.)可以在不更改列的情况下更新列。然后呢?3.)所有1.)和2.)的组合。做得好!但有一个改进:使用是独特的,而不是(在使用SELECT CASE的行中…),否则您将无法将列设置为NULL。是的,这是一个很好的改进。编辑。谢谢