My end user is going to enter query like this:
INSERT INTO course(
id, column_1, column_2, column_3, column_4, column_5)
VALUES ('f34-gr5-t46','ABC', '2022-10-18 07:19:29', 2, 'false', now())
ON CONFLICT (id) DO UPDATE
SET (column_1, column_2, column_3, column_4, column_5)
= (EXCLUDED.column_1, EXCLUDED.column_2, EXCLUDED.column_3, EXCLUDED.column_4, EXCLUDED.column_5);
User is going to either create new record or update using this same query. Whenever there is an update I need to store only updated column’s name, old value, new value and changed time in my audit table.
I have created a function and a trigger like this:
CREATE OR REPLACE FUNCTION log_changes()
RETURNS TRIGGER
LANGUAGE PLPGSQL
AS
$$
BEGIN
IF NEW.column_1 != OLD.column_1 THEN
INSERT INTO course_history(id, course_id, field_name, action_type, old_value, new_value, changed_time)
VALUES(uuid_generate_v4(), OLD.id, 'column_1', 'UPDATE', OLD.column_1, NEW.column_1, new.changed_time);
ELSEIF NEW.column_2 != OLD.column_2 THEN
INSERT INTO course_history(id, course_id, field_name, action_type, old_value, new_value, changed_time)
VALUES(uuid_generate_v4(), OLD.id, 'column_2', 'UPDATE', OLD.column_2, NEW.column_2, new.changed_time);
// and so on for all columns that could be changed in course table
END IF;
RETURN NEW;
END;
$$
CREATE TRIGGER course_changes
BEFORE UPDATE
ON course
FOR EACH ROW
EXECUTE PROCEDURE log_changes();
This function creates new rows for each updated fields in single update. I am trying to reduce repeating code of if condition for each column. How can I achieve that?
Is there a way to combine updates of multiple fields into single row? so that if user updated only two columns in single query, I will have single row showing those updates in history table.
2
Answers
To answer your second question : you can insert only one row with updates on several columns, by using a jsonb column in your table
course_history
in place of fieldsfield_name
,action_type
,old_value
,new_value
, and put only oneINSERT
statement in your trigger function :To answer your first question : you can try using a dynamic sql command in you trigger function :
You can get the column names from
information_schema.columns
. To compare the values for a column, you can use code like: