简体   繁体   中英

How to move values of a row, from a column to another with a trigger function?

I have two tables. A main table and a sort of "backup" table.

The main table looks like this:

  id   |   name   |   a   |   b   
  int  |   text   |  int  |  int   
-------+----------+-------+-------
  1    |   Joe    |  100  |  10   
  2    |   Bill   |  200  |  40  
  3    |   Frank  |  200  |  20   
  4    |   Jack   |  100  |  10  

and the backup table looks like this:

  id   |   name1  |   a1  |   b1  |  name2 |  a2  | b2  |  name3 |  a3 | b3
  int  |   text   |  int  |  int  |  text  |  int | int |  text  | int | int 
-------+----------+-------+-------+--------+------+-----+--------+-----+----
  1    |   Joe    |  100  |  10   |        |      |     |        |     |
  2    |   Bill   |  200  |  40   |        |      |     |        |     |
  3    |   Frank  |  200  |  20   |        |      |     |        |     |
  4    |   Jack   |  100  |  10   |        |      |     |        |     |

What I would like here is if I update my main table (either the name or a or b column), the values in the backup table should move to the "next" columns. Like name1 to name2 , a1 to a2 , b1 to b2 , name2 to name3 etc. So for example if I update Joe to Don , the backup table would look like this:

UPDATE myschema.maintable
SET name = 'Don'
WHERE id = 1;
      id   |   name1  |   a1  |   b1  |  name2 |  a2  | b2  |  name3 |  a3 | b3
      int  |   text   |  int  |  int  |  text  |  int | int |  text  | int | int 
    -------+----------+-------+-------+--------+------+-----+--------+-----+----
      1    |   Don    |  100  |  10   |  Joe   | 100  | 10  |        |     |
      2    |   Bill   |  200  |  40   |        |      |     |        |     |
      3    |   Frank  |  200  |  20   |        |      |     |        |     |
      4    |   Jack   |  100  |  10   |        |      |     |        |     |

Now I know that this is a quite bad way to do a backup table, but unfortunately it is beyond my control, and this is how I have to do it.

What I have tried and expected to work is this:

CREATE OR REPLACE FUNCTION table_update_func()
RETURNS TRIGGER AS
$BODY$
BEGIN
UPDATE myschema.backuptable
SET 
name3 = name2,
a3 = a2,
b3 = b2,
name2 = name1,
b2 = a1,
b2 = b1,
name1 = name,
a1 = a,
b1 = b
FROM myschema.maintable
WHERE maintable.id = backuptable.id;
RETURN NULL;
END;
$BODY$
LANGUAGE plpgsql VOLATILE

CREATE TRIGGER table_update_trig
BEFORE UPDATE 
ON myschema.maintable
FOR EACH ROW
WHEN (OLD.* IS DISTINCT FROM NEW.*)
EXECUTE PROCEDURE table_update_func();

If I update something in the maintale it runs without an error, but it moves the columns in every row, not just the one I updated. Where did I go wrong? I am pretty sure my condition WHERE maintable.id = backup.id; is not good, but I don't know how should I solve this problem.

You are joining the backup table with every row in the maintable that's why you always update all rows in the backup table. You don't need a FROM clause there, as you have the ID of the UPDATE row available in the new record.

CREATE OR REPLACE FUNCTION table_update_func()
RETURNS TRIGGER AS
$BODY$
BEGIN
UPDATE myschema.backuptable 
  SET name3 = name2,
      a3 = a2,
      b3 = b2,
      name2 = name1,
      b2 = a1,
      b2 = b1,
      name1 = new.name, -- reference the values of the new record here
      a1 = new.a,
      b1 = new.b
  WHERE backuptable.id = new.id; --<< no FROM clause necessary
  
  RETURN new; --<< IMPORTANT for a BEFORE UPDATE trigger!
END;
$BODY$
LANGUAGE plpgsql VOLATILE

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM