【问题标题】:PL/pgSQL: How to use IF NEW.<variable_column_name> <> OLD.<variable_column_name>PL/pgSQL:如何使用 IF NEW.<variable_column_name> <> OLD.<variable_column_name>
【发布时间】:2018-10-06 06:31:56
【问题描述】:

我对 PL/pgSQL 编程很陌生。我需要审核记录表中更新的列

表格

create table sample_table(name varchar(15),city varchar(15),age int,mail varchar(20) primary key); 

审核表

create table sample_table__audits_dynamicols(mail varchar(20), columnchanged varchar(10), oldvalue varchar(10), changed_on timestamp(6) NOT NULL)

触发函数

CREATE FUNCTION public.log_sample_table_allchanges() RETURNS trigger AS $BODY$DECLARE
       _colname text;
       _tablename varchar(15) := 'sample_table';
       _schema varchar(15) := 'public';
       _changed_on time := now();
    BEGIN
      FOR _colname IN SELECT column_name FROM information_schema.Columns WHERE table_schema = _schema AND table_name = _tablename LOOP  
         IF NEW._colname <> OLD._colname THEN
            INSERT INTO sample_table__audits_dynamicols(mail,columnchanged, oldvalue ,changed_on)
            VALUES(OLD.mail,_colname,OLD.:_colname,_changed_on);
         END IF;
      END LOOP;
     RETURN NEW;
    END$BODY$
    LANGUAGE plpgsql VOLATILE NOT LEAKPROOF;

触发器

create TRIGGER log_sample_table_allchanges
  BEFORE UPDATE
  ON SAMPLE_TABLE
  FOR EACH ROW
  EXECUTE PROCEDURE log_sample_table_allchanges();

要求:每当更改列值时,我都想将其记录为

(邮件、列名、列值、日期)

例如:

insert into sample_table (name, mail, city, age) values('kanta','mk@foo.com','hyd',23);
insert into sample_table (name, mail, city, age) values('kmk','mk@gmail.com','hyd',23);

所以当我像下面这样更新时

update sample_table set age=24 where mail='mk@foo.com';
update sample_table set city='bza' where mail='mk@gmail.com'

我希望审计表记录如下

(mk@foo.com,age,23, timestamp) 
(mk@gmail.com, city, hyd, timestamp)

现在,我在 Trigger 函数中遇到列比较问题。请帮我纠正我的触发功能以满足我的要求。

【问题讨论】:

  • 你遇到了什么问题?
  • @a_horse_with_no_name 我想遍历 '"sample_table" 的所有列并检查是否更新了任何列值。我在动态访问列名时遇到了问题。我的问题现在已经解决了。请在下方查看 Kaushik 提供的解决方案。

标签: postgresql stored-procedures plpgsql database-trigger


【解决方案1】:

您可以使用EXECUTE 动态获取列的值并进行比较。

CREATE OR REPLACE FUNCTION public.log_sample_table_allchanges() RETURNS trigger AS 
    $BODY$
      DECLARE
       _colname text;
       _tablename varchar(15) := 'sample_table';
       _schema varchar(15) := 'public';
       _changed_on timestamp := now();
       _old_val text;
       _new_val text;
    BEGIN
      FOR _colname IN SELECT column_name FROM information_schema.Columns WHERE table_schema = _schema AND table_name = _tablename
       LOOP  
          EXECUTE 'SELECT $1.' || _colname || ', $2.' || _colname
           USING OLD,NEW
          INTO _old_val, _new_val; --get the old and new values for the column.

          IF _new_val <> _old_val THEN
            INSERT INTO sample_table__audits_dynamicols(mail,columnchanged, oldvalue ,changed_on)
            VALUES(OLD.mail,_colname,_old_val,_changed_on);
         END IF;
      END LOOP;
     RETURN NEW;
    END$BODY$
    LANGUAGE plpgsql VOLATILE NOT LEAKPROOF;

我不确定您为什么在审计表中将mail 定义为PRIMARY KEY,如果同一邮件被更新两次,这将导致unique constraint 违规。

【讨论】:

  • 嗨 Kaushik,是的,您是正确的,审计表中的主键约束不正确。我已经重新创建了我的审计表并修改了我的触发器函数,如您在答案中指定的那样。有效。非常感谢!!!
  • @ManiKantaKandagatla:不客气。顺便说一句,您提出的问题包含了所需的所有详细信息,确切地说是 Stackoverflow 中的问题应该是怎样的。非常感谢。
猜你喜欢
  • 1970-01-01
  • 2010-10-15
  • 1970-01-01
  • 2018-12-19
  • 1970-01-01
  • 2018-12-05
  • 2019-08-24
  • 1970-01-01
  • 2012-10-19
相关资源
最近更新 更多