简体   繁体   中英

How to upsert values in Postgres catching exceptions while identifying modifications to a table

I have two tables in Postgres, t_product and t_product_modifications having the following respective structures:

t_product

product_code    product_category     owner
============    ================     =====
  A                home               Jack
  B                office             Daniel
  C                outdoor            Jack
  D                home               Susan

(the 'product_code' and 'product_category' are unique together and is a composite primary key. 
There is also a NOT NULL constraint on the 'owner' column)

t_product_modifications

product_code       last_modified_time
============       ==================
 A                 2020-04-07 16:10:30
 B                 2020-04-07 16:10:30
 C                 2020-04-07 16:10:30
 D                 2020-04-07 16:10:30

I basically need to do a bulk insert/update into the t_product table. And only if there has been a modification to a record, i should update the last_modified_time column in the t_product_modifications table. In addition to this, it is important that the entire bulk upsert should not fail if some other constraints have failed for certain records but rather it should just return a list of product_codes or an error log for which the upserts were not possible. (Also, for certain reasons I can't have both tables as one)

For example, let us say i am trying to do a bulk upsert for the following values into the t_product table:

1. ('A','home', 'Susan')
2. ('B','office', 'Daniel')
3. ('E','office', NULL)
4. ('F','home', NULL)

When trying to insert the above four values, this is what needs to happen

  1. The first record should be updated successfully for ('A','home') primary key and the value Susan should be updated in the owner column. Since this record was an update to the t_product table, the last_modified_time for the respective product should be updated in the t_product_modifications table.
  2. Ignore the second record. Basically it should not make any changes to the t_product_modifications table since there are no modifications being made to the t_product table
  3. The third record should be a part of the output error log or exception since the owner field cannot be NULL
  4. the fourth record should be a part of the output error log or exception since the owner field cannot be NULL

I will be executing this Postgres query from a Python script and wish to save all errors that happened during upsert without the entire query failing. I was unable to find a solution on StackOverflow that was efficient enough.

Trigger procedures are perfect for solving your problem. You need to create a procedure that will be executed when a record of the t_product table is updated and check if the values of the columns have changed, if true, then update the last_modified_time column from the t_product_modifications table.

Your Trigger:

CREATE FUNCTION update_product() RETURNS TRIGGER AS $$
  BEGIN
    IF (TG_OP = 'UPDATE') AND OLD!=NEW THEN
       UPDATE t_product_modifications SET last_modified_time = NOW() WHERE product_code = New.product_code;
    END IF;
    RETURN NEW; 
  END; $$ LANGUAGE plpgsql;
  
CREATE TRIGGER update_product_modified_time BEFORE UPDATE ON t_product FOR EACH ROW EXECUTE PROCEDURE update_product();

Demo in DBfiddle


 -- This will update the last_modified_time in the t_product_modifications table
    UPDATE t_product SET product_category = 'home', owner = 'Susan'  WHERE product_code = 'A'; 

 -- Nothing will happen
    UPDATE t_product SET product_category = 'office', owner = 'Daniel' WHERE product_code = 'B'; 
    

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