Reputation: 407
I have an invoices
table like this :
CREATE TABLE invoices (
idinvoice SERIAL PRIMARY KEY
,idclient INTEGER REFERENCES clients(idclient)
-- other fields here
);
and an invoiceitems
table :
CREATE TABLE invoiceitems (
idinvoiceitem SERIAL PRIMARY KEY
,idinvoice INTEGER REFERENCES invoices(idinvoice)
,amount NUMERIC(15,2)
,sortorder INTEGER DEFAULT 10
);
My problem is with the sortorder
field : every time I insert or update an invoiceitem, I want the sortorder
s of all items of the same invoice to be recalculated with a query like this :
WITH pre AS (
SELECT idinvoiceitem,10*ROW_NUMBER() OVER (ORDER BY sortorder,idinvoiceitem) AS rownum
FROM invoiceitems
WHERE idinvoice=xx
ORDER BY sortorder,idinvoiceitem
)
UPDATE invoiceitems di
SET sortorder=rownum
FROM pre p
WHERE p.idinvoiceitem=di.idinvoiceitem;
That way, every time a new item is added, it will be numbered 10+last item, and if I decide to change the sort order of the item by manually setting a value, all the sortorder
s will be recalculated with a 10 increment :
id | sortorder
---+----------
1 | 10
2 | 20
3 | 30
4 | 40 ← I change this to 25
Then after the query, I will get :
id | sortorder
---+----------
1 | 10
2 | 20
4 | 30
3 | 40
I would like to have this in a trigger. The problem is that item #4 will be UPDATEd by the trigger (thus calling the trigger again) and I will get some kind of endless recursion.
Is there a way to do this ? For example, set some semaphore that would prevent the trigger from being called when the UPDATE occurs within the trigger itself ? Or maybe an explicit LOCK ?
(using PostgreSQL 11+)
Upvotes: 2
Views: 185
Reputation: 1066
One thing you could do is to use pg_trigger_depth()
function, which is documented here.
Then your trigger should look similar to this:
CREATE TRIGGER trigger_name
AFTER UPDATE OR INSERT ON invoiceitem
FOR EACH ROW
WHEN (pg_trigger_depth() = 0)
EXECUTE PROCEDURE your_procedure();
I'd recommend read some discussions about this approach (1, 2), but in general for not complicated systems this should be fine.
Upvotes: 1