简体   繁体   中英

PostgreSQL Update TRIGGER Fires Multiple Times When Just 1 Row Updated

Source Table :-

CREATE TABLE schema1.Source_Table
(
    Source_Table_id serial NOT NULL,
    current_status_id smallint NOT NULL,
    current_status_reason varchar(200) NULL,
    requestor_id integer NOT NULL,
    approver_id integer NULL,
    last_upd_user_id integer NOT NULL,
    last_upd_date_time timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
    CONSTRAINT PK_Source_Table PRIMARY KEY (Source_Table_id)
)
WITH OIDS;

Destination Table (Audit History Purpose) :-

CREATE TABLE schema2.Destination_Table
(
    type_id smallint NOT NULL,
    id integer NOT NULL,
    state_id smallint NOT NULL,
    state_reason varchar(200) NULL,
    requestor_id integer NOT NULL,
    approver_id integer NULL,
    upd_by_user_id integer NOT NULL,
    upd_by_user_type smallint NOT NULL,
    upd_date_time timestamp without time zone NOT NULL
)
WITH OIDS;

After Update for each Row Trigger on the Source Table :-

CREATE TRIGGER trg_upd_Source_Table
   AFTER UPDATE of current_status_id
   ON schema1.Source_Table
   FOR EACH ROW
  WHEN (OLD.current_status_id IS DISTINCT FROM NEW.current_status_id)
      EXECUTE PROCEDURE schema1.Source_Table_hist();

Trigger Function for the After Update for each Row Trigger above :-

CREATE OR REPLACE FUNCTION schema1.Source_Table_hist()
RETURNS TRIGGER
LANGUAGE PLPGSQL
AS $$
BEGIN
    INSERT INTO schema2.Destination_Table
        (type_id, id, state_id, state_reason, requestor_id, approver_id, upd_by_user_id, 
        upd_by_user_type, upd_date_time)
    SELECT 1, OLD.Source_Table_id, OLD.current_status_id, OLD.current_status_reason, 
        OLD.requestor_id, OLD.approver_id, OLD.last_upd_user_id, 1, OLD.last_upd_date_time
    from schema1.Source_Table
    where OLD.current_status_id IS DISTINCT FROM NEW.current_status_id;
    RETURN NULL;
END;
$$

There are already 8 rows in schema1.Source_Table table with the unique primary key Source_Table_id. When I update just 1 row of this table as below using the primary key, it inserts 8 rows (1 original and 7 duplicates) into the schema2.Destination_Table table instead of just 1 row.

update schema1.Source_Table
set current_status_id = 4
where Source_Table_id = 9;

The issue here is :- Why the trigger is firing for 8 times (which is equals to the total number of rows in the table on which this trigger is created) when only 1 row of that table is updated.

Expected Behavior :- The Trigger should fire only once followed by inserting 1 row in the destination audit table when just 1 row is updated in the source table on which the trigger is created.

How to solve this issue ?

The trigger isn't firing multiple times, your query is inserting a row into the hist table for every row in the source table:

    INSERT INTO schema2.Destination_Table
    (type_id, id, state_id, state_reason, requestor_id, approver_id, upd_by_user_id, 
    upd_by_user_type, upd_date_time)
SELECT 1, OLD.Source_Table_id, OLD.current_status_id, OLD.current_status_reason, 
    OLD.requestor_id, OLD.approver_id, OLD.last_upd_user_id, 1, OLD.last_upd_date_time
from schema1.Source_Table
where OLD.current_status_id IS DISTINCT FROM NEW.current_status_id;
RETURN NULL;

I don't think you need that from clause.

The problem is in the WHERE condition:

where OLD.current_status_id IS DISTINCT FROM NEW.current_status_id

This condition is known to be true from the WHEN condition on the trigger. As it is the only WHERE effective it is the same no WHERE condition at all, there fore all roes are processed by the insert. Suggest

where current_status_id = OLD.current_status_id

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