'postgresql - on update trigger

I'm trying to do on update trigger, which will be automatically updating current_timestamp only when column updated_date is not openly updated.

function:

CREATE OR REPLACE FUNCTION dba.update_stamp_pc() RETURNS trigger
LANGUAGE plpgsql
AS $$
BEGIN
    RAISE NOTICE 'NEW.updated_date: %', NEW.updated_date;
    RAISE NOTICE 'OLD.updated_date: %', OLD.updated_date;
    IF NEW.updated_date=OLD.updated_date OR NEW.updated_date is null then
        NEW.updated_date := current_timestamp;
    END IF;
    RETURN NEW;
END;
$$;

Checks:

aaa=> insert into dba.pc_test1 values(7);
INSERT 0 1
aaa=> select order_id,created_date,updated_date from dba.pc_test1 where order_id=7;
 order_id |         created_date          | updated_date 
----------+-------------------------------+--------------
    7 | 2022-02-23 10:01:23.142326+00 | 
(1 row)
aaa=> update dba.pc_test1 set order_id=7 where order_id=7;
NOTICE:  NEW.updated_date: <NULL>
NOTICE:  OLD.updated_date: <NULL>
UPDATE 1
aaa=> select order_id,created_date,updated_date from dba.pc_test1 where order_id=7;
 order_id |         created_date          |        updated_date         
----------+-------------------------------+-----------------------------
    7 | 2022-02-23 10:01:23.142326+00 | 2022-02-23 10:02:04.5021+00
(1 row)
aaa=> \d dba.pc_test1
                            Table "dba.pc_test1"
Column    |            Type             | Collation | Nullable |         Default         
--------------+-----------------------------+-----------+----------+-------------------------
 order_id     | bigint                      |           | not null | 
 created_date | timestamp(6) with time zone |           | not null | 
 created_by   | character varying(50)       |           | not null | 
 updated_date | timestamp(6) with time zone |           |          | 
 updated_by   | character varying(50)       |           |          | NULL::character varying
Triggers:
    insert_pc_test1 BEFORE INSERT ON dba.pc_test1 FOR EACH ROW EXECUTE FUNCTION dba.insert_stamp_pc()
    update_pc_test1 BEFORE UPDATE ON dba.pc_test1 FOR EACH ROW EXECUTE FUNCTION dba.update_stamp_pc()

aaa=> update dba.pc_test1 set order_id=7 where order_id=7;
NOTICE:  NEW.updated_date: 2022-02-23 10:02:04.5021+00
NOTICE:  OLD.updated_date: 2022-02-23 10:02:04.5021+00
UPDATE 1
aaa=> select order_id,created_date,updated_date from dba.pc_test1 where order_id=7;
 order_id |         created_date          |         updated_date          
----------+-------------------------------+-------------------------------
   7 | 2022-02-23 10:01:23.142326+00 | 2022-02-23 10:03:03.571949+00
(1 row)
aaa=> update dba.pc_test1 set order_id=7,updated_date='2000-01-01' where order_id=7;
NOTICE:  NEW.updated_date: 2000-01-01 00:00:00+00
NOTICE:  OLD.updated_date: 2022-02-23 10:03:03.571949+00
UPDATE 1
aaa=> select order_id,created_date,updated_date from dba.pc_test1 where order_id=7;
 order_id |         created_date          |      updated_date      
----------+-------------------------------+------------------------
7 | 2022-02-23 10:01:23.142326+00 | 2000-01-01 00:00:00+00
(1 row)
aaa=> update dba.pc_test1 set order_id=7,updated_date='2000-01-01' where order_id=7;
NOTICE:  NEW.updated_date: 2000-01-01 00:00:00+00
NOTICE:  OLD.updated_date: 2000-01-01 00:00:00+00
UPDATE 1
aaa=> select order_id,created_date,updated_date from dba.pc_test1 where order_id=7;
 order_id |         created_date          |         updated_date          
----------+-------------------------------+-------------------------------
   7 | 2022-02-23 10:01:23.142326+00 | 2022-02-23 10:03:45.473659+00
(1 row)
aaa=> 

In the last case, updated_date should have value '2000-01-01 00:00:00+00', but because inside the database such value already exists then the current_timestamp is inserted. How to fix it?



Solution 1:[1]

I created a sample trigger function and tested it, 100% working. Example:

CREATE OR REPLACE FUNCTION update_test_table() 
returns trigger
language plpgsql
AS $$
begin
    
    if new.action_date = old.action_date or new.action_date is null then
        new.action_date := current_timestamp;
    end if;
   
    return new;
end;
$$;


CREATE TRIGGER trigger_update_test_table
BEFORE UPDATE
ON test_table
FOR EACH ROW
  EXECUTE PROCEDURE update_test_table();

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Ramin Faracov