Get values from varying columns in a generic trigg

2020-02-14 20:45发布

问题:

I am new to PostgreSQL and found a trigger which serves my purpose completely except for one little thing. The trigger is quite generic and runs across different tables and logs different field changes. I found here.

What I now need to do is test for a specific field which changes as the tables change on which the trigger fires. I thought of using substr as all the column will have the same name format e.g. XXX_cust_no but the XXX can change to 2 or 4 characters. I need to log the value in theXXX_cust_no field with every record that is written to the history_ / audit table. Using a bunch of IF / ELSE statements to accomplish this is not something I would like to do.

The trigger as it now works logs the table_name, column_name, old_value, new_value. I however need to log the XXX_cust_no of the record that was changed as well.

回答1:

Basically you need dynamic SQL for dynamic column names. format helps to format the DML command. Pass values from NEW and OLD with the USING clause.

Given these tables:

CREATE TABLE tbl (
  t_id serial PRIMARY KEY
 ,abc_cust_no text
);

CREATE TABLE log (
  id          int
 ,table_name  text
 ,column_name text
 ,old_value   text
 ,new_value   text
);

It could work like this:

CREATE OR REPLACE FUNCTION trg_demo()
  RETURNS TRIGGER AS
$func$
BEGIN

EXECUTE format('
   INSERT INTO log(id, table_name, column_name, old_value, new_value)
   SELECT ($2).t_id
         , $3
         , $4
         ,($1).%1$I
         ,($2).%1$I', TG_ARGV[0])
USING OLD, NEW, TG_RELNAME, TG_ARGV[0];

RETURN NEW;

END
$func$ LANGUAGE plpgsql;

CREATE TRIGGER demo
BEFORE UPDATE ON tbl
FOR EACH ROW EXECUTE PROCEDURE trg_demo('abc_cust_no'); -- col name here.

SQL Fiddle.

Related answer on dba.SE:

  • How to access NEW or OLD field given only the field's name?

List of special variables visible in plpgsql trigger functions in the manual.