Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
287 views
in Technique[技术] by (71.8m points)

Postgresql 12 trigger updatewith dynamic SQL EXECUTE

I have a parent table orders with an id and a timestamp updated_at :

+-----+-------------------------------+
| id  |          updated_at           |
+-----+-------------------------------+
| 808 | 2020-09-23 15:14:13.077086+02 |
+-----+-------------------------------+

I have child tables order_products, order_delivery, order_billing, order_tracking etc. with foreign keys and order_id field for each :

+----------+---------+---------+---------+
| order_id | field_x | field_y | field_z |
+----------+---------+---------+---------+
|      808 | x       | y       | z       |
+----------+---------+---------+---------+

I want to update orders.updated_at each time a field is updated in a child table. But I do not want to create a different trigger function for each child table, so I created this trigger function :

CREATE OR REPLACE FUNCTION public.update_orders_updated_at_from_sub_orders()
    RETURNS trigger
    LANGUAGE 'plpgsql'
    COST 100
    VOLATILE NOT LEAKPROOF
AS $BODY$
BEGIN
    EXECUTE format('UPDATE orders SET updated_at = NOW() FROM %I WHERE orders.id = %I.order_id;',TG_TABLE_NAME,TG_TABLE_NAME);
    RETURN NEW;
END;
$BODY$;

I use TG_TABLE_NAME to find on which child table the trigger is triggred. The problem is that for an update on any child table for a specific order_id, it updates ALL "orders.updated_at" and not only the specific "orders.id". I should use the record NEW somewhere but can't figure out how because I'm using dynamic SQL to factorise the trigger function. Any idea ?

SOLUTION 1 :

CREATE OR REPLACE FUNCTION public.update_orders_updated_at_from_sub_orders()
    RETURNS trigger
    LANGUAGE 'plpgsql'
    COST 100
    VOLATILE NOT LEAKPROOF
AS $BODY$
    DECLARE new_order_id INTEGER;
BEGIN
    new_order_id = NEW.order_id;
    EXECUTE format('UPDATE orders SET updated_at = NOW() FROM %I WHERE orders.id = %I.order_id AND orders.id = %s::INT;',TG_TABLE_NAME,TG_TABLE_NAME,new_order_id);
    RETURN NEW;
END;
$BODY$;

Not sure it is "clean" SQL though


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)
CREATE OR REPLACE FUNCTION public.update_orders_updated_at_from_sub_orders()
    RETURNS trigger
    LANGUAGE 'plpgsql'
    COST 100
    VOLATILE NOT LEAKPROOF
AS $BODY$
BEGIN
    UPDATE orders SET updated_at = NOW() WHERE id = NEW.order_id;
    RETURN NEW;
END;
$BODY$;

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...