My question is best illustrated with an example:
Let's say we have two tables:
CREATE TABLE usr_static (
id bigint,
dob text,
...
);
CREATE TABLE usr_version (
id bigint,
name text,
gender text,
...
)
And a view:
CREATE VIEW usr AS
SELECT usr_static.id, usr_static.dob, usr_version.name, usr_version.gender, ...
FROM usr_static
LEFT JOIN usr_version ON usr_static.id = usr_version.id;
Now I am trying to create a trigger function for this view that intercepts an INSERT into the view and splits it up into 2 inserts: 1 for the usr_static table and 1 for the usr_version table:
INSERT INTO usr (5, '2023-05-11', 'John', 'male');
-- -->
INSERT INTO usr_static (5, '2023-05-11');
INSERT INTO usr_version ('John', 'male')
My trigger function would then look like:
CREATE FUNCTION my_trigger_func() RETURNS trigger
LANGUAGE plpgsql
AS $$
BEGIN
IF (TG_OP = 'INSERT') THEN
INSERT INTO usr_static (
dob
) VALUES (
NEW.dob,
) RETURNING id INTO NEW.id;
INSERT INTO usr_version (
id,
name,
gender
) VALUES (
NEW.id,
NEW.name,
NEW.gender
);
RETURN NEW;
END IF;
END;
$$;
This is a very common pattern in the application that I'm working on. So I was wondering if there is a way to create one trigger that I can apply to multiple views?
So my question is, if it is somehow possible to do something like:
INSERT INTO %_static VALUES (NEW.*) RETURNING id INTO NEW.id;
INSERT INTO %_version VALUES (NEW.*);
Here the % would get replaced with the name of the view (usr in this case). The tricky part here is to somehow dynamically map the values on NEW to the correct table. In other words, without explicitly mapping the columns in the INSERT statement to the values on NEW as in the above function. E.g. the value NEW.dob, would get inserted in the dob column on usr_static.
I hope I have explained my question clearly.
Thank you so much for any help :)
While it's possible to create a trigger function that could be applied to multiple views to perform the described inserts, it's not advisable. A function that worked for the general case would need to query the system catalogs to dynamically create insert statements for each row inserted into a view. This approach would not be very performant. A better approach is to create dedicated functions for each view.
The following demonstates a function that queries the system catalogs to generate a trigger function definition to populate a view's base tables. (This approach can be expanded to handle
DELETEandUPDATEas well.)In addition to matching by column name, it might also be desirable to address foreign key reference columns between a view's base tables. It might also be useful to enhance the
INSERTs to handle conflicts, especially if some of the columns are associated with a parent table with multiple child rows.