'PostgreSQL- Function to update 3 shared columns from table B on table A
The main goal is to create a function that updates 3 columns on another table (the update of the 2 columns from the first table trigger the update on the second one).
CREATE TRIGGER trigger_modif_amount
AFTER INSERT OR DELETE OR UPDATE OF net_amount, iva_amount
ON erp.tb_lines
FOR EACH ROW
EXECUTE PROCEDURE modif_amount();
The name of the 3 columns: net_amount , iva_amount , total_amount
CREATE OR REPLACE FUNCTION modif_amount()
RETURNS TRIGGER AS $$
BEGIN
UPDATE erp.tb_invoice
SET (net_amount,iva_amount,tot_amount) = (select COALESCE(sum(net_amount),0),COALESCE(sum(iva_amount),0),COALESCE(sum(net_amount+iva_amount),0) from tb_lines where invoice_id = coalesce(NEW.invoice_id, OLD.invoice_id))
WHERE invoice_id = coalesce(NEW.invoice_id, OLD.invoice_id);
END;
$$ LANGUAGE plpsql;
The tables:
CREATE TABLE erp.tb_invoice (
co_code CHARACTER(3) NOT NULL,
invoice_id INT NOT NULL,
invoice_no CHARACTER VARYING(15) NOT NULL,
cust_no CHARACTER(5) NOT NULL,
site_id INT NOT NULL,
payed CHARACTER(1) NOT NULL DEFAULT 'N',
net_amount REAL NOT NULL,
iva_amount REAL NOT NULL,
tot_amount REAL NOT NULL,
last_updated_by CHARACTER VARYING(20) DEFAULT 'SYSTEM',
last_update_date DATE NOT NULL,
CONSTRAINT pk_invoice PRIMARY KEY (invoice_id),
CONSTRAINT fk_invoice_company FOREIGN KEY (co_code) REFERENCES erp.tb_company (co_code),
CONSTRAINT fk_invoice_customer FOREIGN KEY (cust_no) REFERENCES erp.tb_customer (cust_no),
CONSTRAINT fk_invoice_site FOREIGN KEY (site_id) REFERENCES erp.tb_site (site_id)
);
CREATE TABLE erp.tb_lines (
invoice_id INT NOT NULL,
line_id INT NOT NULL,
line_num INT NOT NULL,
item CHARACTER(5),
description CHARACTER VARYING(120) NOT NULL,
net_amount REAL NOT NULL,
iva_amount REAL NOT NULL,
last_updated_by CHARACTER VARYING(20) DEFAULT 'SYSTEM',
last_update_date DATE NOT NULL,
CONSTRAINT pk_lines PRIMARY KEY (line_id),
CONSTRAINT fk_lines_invoice FOREIGN KEY (invoice_id) REFERENCES erp.tb_invoice (invoice_id)
);
Solution 1:[1]
This trigger definition to only execute the function (modif_amount) if column (net_amount) and (iva_amount) is specified as a target in the UPDATE command:
CREATE TRIGGER trigger_modif_amount
AFTER UPDATE OF net_amount,iva_amount ON tb_lines
FOR EACH ROW
EXECUTE PROCEDURE modif_amount();
This form only executes the function (modif_amount) if column (net_amount), (iva_amount) has in fact changed value:
CREATE TRIGGER trigger_modif_amount
AFTER UPDATE
ON tb_lines
FOR EACH ROW
WHEN ((OLD.net_amount IS DISTINCT FROM NEW.net_amount) AND
(OLD.iva_amount IS DISTINCT FROM NEW.iva_amount) )
EXECUTE PROCEDURE modif_amount();
Solution 2:[2]
You can create trigger which trigger after update of specific fields
https://www.postgresql.org/docs/14/sql-createtrigger.html
CREATE TRIGGER test
AFTER INSERT OR DELETE OR UPDATE OF net_amount, iva_amount
ON tb_lines
FOR EACH ROW
EXECUTE PROCEDURE modif_amount();
Updating overal sum in another table inside trigger is not a good idea (it moves business logic into triggers and is not save).
Version 1
update tb_invoice set
(net_amount,iva_amount,tot_amount) = (select COALESCE(sum(net_amount),0),COALESCE(sum(iva_amount),0),COALESCE(sum(net_amount+iva_amount),0) from tb_lines where invoice_id = coalesce(NEW.invoice_id, OLD.invoice_id))
where invoice_id = coalesce(NEW.invoice_id, OLD.invoice_id);
Version 2
update tb_invoice set
(net_amount,iva_amount,tot_amount) = (select COALESCE(sum(net_amount),0),COALESCE(sum(iva_amount),0),COALESCE(sum(net_amount+iva_amount),0) from tb_lines where tb_lines.invoice_id = tb_invoice.invoice_id)
where invoice_id = coalesce(NEW.invoice_id, OLD.invoice_id);
COALESCE in sum is needed to ensure, that even if invoice has no positions sums will be calculated as 0.
COALESCE in where is needed because during insert operation there is no OLD.invoice_id, and during delete operation there is no NEW.invoice_id.
My assumption is, that invoice_id cannot be changed. If not, that moving a position from one invoice to another should update ole and new one.
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 | |
Solution 2 |