Apply a single trigger procedure to many different tables - postgresql

In my PostgreSQL 9.1 database I have multiple tables and one trigger function.
Right now I am creating the trigger for each table by using that trigger function.
This methodology working fine. My boss has asked me to create the trigger commonly (only one time) by re-using that trigger function. That one trigger function should get used by all the tables in my database.

You can find an example of creating a trigger with dynamic SQL using PL/PgSQL in the Audit Trigger sample for PostgreSQL. The same approach will work with any other DDL.
See the function audit.audit_table and use of format and EXECUTE there.
That said, needing to create tables procedurally can be (but isn't always) a sign of questionable schema design.
Simple example of dynamic SQL creating a table:
CREATE OR REPLACE FUNCTION demo_dynamic_table(tablename text) RETURNS void AS $$
BEGIN
EXECUTE format('CREATE TABLE %I (id serial primary key);', tablename);
END;
$$ LANGUAGE plpgsql;
The same approach works for trigger creation, etc.

You can create PL/pgSQL procedure for table creation and move your trigger creation code inside it

Related

Can I create and access a table in the same SQL function?

I am trying to create a Postgres SQL-function which runs some routine for my database.
The SQL-function calls a plpgsql-function which creates several temporary tables, but doesn't return anything (RETURNS void).
One of the tables created by the plpgsql-function is supposed to be used in my sql-function.
CREATE OR REPLACE FUNCTION public.my_sql_function()
RETURNS text AS
$BODY$
select public.my_plpsql_function(); -- this returns void, but has created a temp table "tmp_tbl"
DROP TABLE IF EXISTS mytable CASCADE;
CREATE TABLE mytable (
skov_id int8 PRIMARY KEY,
skov_stor int4,
skov_areal_ha numeric,
virkningfra timestamp(0) without time zone,
plannoejagtighed float8,
vertikalnoejagtighed float8,
geom geometry(MultiPolygon,25832),
orig_geom geometry(Polygon, 25832)
);
INSERT INTO mytable
select * from tmp_tbl ....
$BODY$ LANGUAGE sql;
When I try to run the lines, I get the following error:
ERROR: relation "tmp_tbl" does not exist
pgAdmin underlines the line select * from tmp_tbl ... as the part with an error.
So the SQL-function doesn't notice that the plpsql-function has created a temporary table.
Is there a workaround?
Creating and accessing a table in the same SQL function is generally impossible. Makes no difference whether you create the table in the SQL function directly or in a nested function call. All objects must be visible to begin with.
There is a big, fat note at the top of the chapter Query Language (SQL) Functions in the manual pointing that out:
Note
The entire body of a SQL function is parsed before any of it is
executed. While a SQL function can contain commands that alter the
system catalogs (e.g., CREATE TABLE), the effects of such commands
will not be visible during parse analysis of later commands in the
function. Thus, for example, CREATE TABLE foo (...); INSERT INTO foo VALUES(...); will not work as desired if packaged up into a single
SQL function, since foo won't exist yet when the INSERT command is
parsed. It's recommended to use PL/pgSQL instead of a SQL function in
this type of situation.
Related:
Why can PL/pgSQL functions have side effect, while SQL functions can't?
Difference between language sql and language plpgsql in PostgreSQL functions
I think so it is not possible - and minimally it should not by possible in future versions. SQL functions are similar to views, and then references to database object should be valid in function's creating time.
There is not any workaround - if you need temp table, use PLpgSQL, or try to write your code without temp table (it can be much better).

Triggers to refresh multiple materialized views based on same table

I have a spatial table in a Postgres database from which I create three separate materialized views (each based on specific spatial queries). I want to create trigger functions to refresh each of the materialized views on updates, inserts, and deletes.
I have created three separate functions and triggers, but the performance (as to be expected) is horrendous. If I run a single trigger on update, insert, or delete, it performs fine. Below is a sample function and trigger I am using:
CREATE OR REPLACE FUNCTION refresh_mvw_taxa_hex5km()
RETURNS trigger
AS $BODY$
BEGIN
refresh materialized view mvw_taxa_hex5km;
return new;
END;
$BODY$ LANGUAGE plpgsql;
CREATE TRIGGER refresh_mvw_taxa_hex5km
AFTER INSERT OR UPDATE OR DELETE ON occurrence
FOR EACH STATEMENT
EXECUTE PROCEDURE refresh_mvw_taxa_hex5km();
Is there a more efficient way to do this? I considered running scheduled tasks, but I really need the refresh on changes to the table. I have read a little about "concurrently," but not sure if this is the answer.

Triggers in postgresql

I am new to PostgreSQL and I am currently working on triggers but am stuck at one point.
I have two tables Student and Room.
Room id is the primary key in Room and foreign key in Student.
If I am inserting in Student, then it should check in Room whether the new data exist or not.
This is a foreign key check constraint. I hope anyone can help me with it
I dont know your code and I dont get the meaning, but I can answer generally.
In PostgreSQL a trigger is normally defined in two steps:
Define a trigger function using the CREATE FUNCTION
Bind this created trigger function to a table using CREATE TRIGGER
A trigger function is a common function, except that is has a return value type trigger (in addition, it does not take any arguments).
CREATE OR REPLACE FUNCTION trigger_function()
RETURNS trigger
AS $$ ... $$;
binding:
CREATE TRIGGER trigger_name
AFTER INSERT ON table_name
FOR EACH ROW EXECUTE PROCEDURE trigger_function();
In addition, please also consult the excellent PG documentation at PostgreSQL 9.4 Triggers

postgresql trigger not working

i have a table "demand_details"
on update or delete i want to store values of each row in another table "demand_details_log"
my functions is as follows
CREATE OR REPLACE FUNCTION water_blogb() RETURNS trigger AS
$BODY$
BEGIN
IF (TG_OP='UPDATE') THEN
INSERT INTO demand_details_log VALUES ('U',now(),OLD.*);
RETURN NEW;
END IF;
IF (TG_OP='DELETE') THEN
INSERT INTO demand_details_log VALUES ('D',now(),OLD.*);
RETURN OLD;
END IF;
END;
$BODY$ LANGUAGE plpgsql
my trigger is as follows
CREATE TRIGGER water_btrg_b
AFTER UPDATE OR DELETE
ON demand_details
FOR EACH ROW
EXECUTE PROCEDURE water_blogb();
MY problem is the same trigger and functions works well on other table (by changing table,trigger and function name) but not working with demand table. I tried with "RAISE NOTICE 'working...'" in both in other table trigger gets fired but in demand table its not fired at all.
As you found, triggers are not inherited. This leads to some difficulties in managing triggers in inherited table structures. You may want to read up on some of the issues involved at http://ledgersmbdev.blogspot.com/2012/08/postgresql-or-modelling-part-3-table.html and http://ledgersmbdev.blogspot.com/2012/08/or-modelling-32-setsubset-modelling.html.
Now those do not address table partitioning directly which may be what you are trying to do here. I would recommend that you build in some additional tests that you can run to check and make sure that triggers are properly installed on all subtables. I would suggest taking a look at How to find inherited tables programatically in PostgreSQL? and also the pg_trigger table so that you can build a report of child tables which do not share the triggers of their parents.

execute a trigger when I create a table

I would like to know if a trigger on a system table of PostgreSQL can be executed when I create a table
I need to add 2 functions on each table of my database and I would like to do it dynamically
Thanks
This can be done with an event trigger:
CREATE OR REPLACE FUNCTION on_create_table_func()
RETURNS event_trigger AS $$
BEGIN
-- your code here
END
$$
LANGUAGE plpgsql;
CREATE EVENT TRIGGER
on_create_table ON ddl_command_end
WHEN TAG IN ('CREATE TABLE')
EXECUTE PROCEDURE on_create_table_func();
Note that there is no way to directly execute any query on the newly created table, or even get its name.
I don't know what you mean by "add 2 functions on each table" since functions don't belong to a specific table, but if you need to perform an operation specific for the new tables, this might not be for you.
I know it's an old question but now it has been implemented in version 9.3, or at least partially
http://www.postgresql.org/docs/9.3/static/event-trigger-definition.html
You're looking for "DDL Triggers". They're not implemented in PostgreSQL. Neither you can add triggers to system tables. Look at this forum entry:
Adding ddl audit trigger