I am new to Postgres (9.0.5) and have written very few functions/triggers in general. I would like to set up a trigger on my widgets table such that every time a widget is inserted, updated or deleted, the entire record is passed to a stored procedure as an argument. The procedure can then inspect the record for various changes and decide what action to take. Here's my best attempt so far, though I know I'm way off course:
CREATE OR REPLACE TRIGGER tg_widgets
ON TABLE widgets
AFTER EVERY INSERT, UPDATED, DELETE
DO run_widget_handler
CREATE OR REPLACE PROCEDURE run_widget_handler AS
# Definitition here
# If the widget's name was changed, do X
# Else if the widget's wow_factor was changed, do Y
# Else, do Z
I'm not worried about how to implement the definition of run_widget_handler, just looking for help and writing the trigger and passing the widget to the proc. Thanks in advance.
You don't need to "pass" the row to the trigger function (btw: there is no "procedure" in PostgreSQL, only functions).
If the function is declared as "returns trigger", you can automatically access the complete row as "new" or "old".
More details in the manual: http://www.postgresql.org/docs/current/static/plpgsql-trigger.html
Related
We have this pair of trigger and function that we use on our psql database for the longest time. Basically, the trigger is called each time there is a new record to the main table, and each row is inserted to the monthly partition individually. Following is the trigger function:
CREATE TRIGGER partition_mic_teams_endpoint_trg1
BEFORE INSERT ON "mic_teams_endpoint"
FOR EACH ROW EXECUTE
PROCEDURE trg_partition_mic_teams_endpoint('month');
The function we have creates monthly partitions based on a timestamp field in each row.
I have two questions:
List item Even if I try to COPY a bunch of rows from CSV to the main table, is this trigger/function going to insert each row individually? Is this efficient?
If that is the case, is it possible to have support for COPYing data to partitions instead of INSERT.
Thanks,
Note: I am sorry if I did not provide enough information for an answer
Yes, a row level trigger will be called for each row separately, and that will make COPY quite a bit slower.
One thing you could try is a statement level AFTER trigger that uses a transition table, so that you can
INSERT INTO destination SELECT ... FROM transition_table;
That should be faster, but you should test it to be certain.
See the documentation for details.
I am seeking suggestions on methods to trigger the running of code based on specific event occurring.
Basically I need to monitor all inserts into a table and compare a column value against a parameter set in another table.
For example, when a new record is added to the table and the column [Temperature] is greater than 30 (which is a value set in another table). Send an alert email to notify of this situation.
You can create a trigger (special type of stored procedure) that is automatically executed after an insert happened. Documentation for triggers is here: https://technet.microsoft.com/en-us/library/ms189799(v=sql.120).aspx
You will not be able to send an email out of SQL Database though.
Depending on how quick you need the notification after the insert, maybe you could make an insert into yet another table from within the trigger and query this new table periodically (e.g. using a script in Azure automation) and have the email logic outside the database.
I am using Postgres 9.3.
I just added a trigger to a table.
It is an after insert trigger which is executed for each row after each statement.
I coded the trigger function assuming the index of the same table contains the newly added rows.
If this is not true, mass inserts will slow down significantly.
I google it a bit but couldn't find an answer.
So, to sum up my questions is after a statement, is index updated before or after the "after insert trigger for each statement" in Postgres 9.3?
Here is the trigger definition I've used:
CREATE TRIGGER trigger_name
AFTER INSERT OR UPDATE
ON table_name
FOR EACH STATEMENT
EXECUTE PROCEDURE trigger_funtion();
An AFTER trigger FOR EACH ROW will see that row in the table. For that to happen reliably the row must have already been added to any indexes. So the index has been updated.
However, if you attempt to modify the table that caused the AFTER trigger to be fired within the AFTER trigger, this usually results in an infinite loop and an error. It is rarely the correct thing to do.
Usually when you're trying to do that, you actually want a BEFORE trigger that modifies the row before it is saved.
If you need to modify some other row in the same table, that often suggests a data model problem. You should very rarely, if ever, need to modify one row in a table using a trigger when a different row is modified.
I'm trying to create a trigger on my table such that it only runs if the 'prepaid' column is true for rows where I've modified the value of the 'points_per_month' column. I tried this:
CREATE TRIGGER "fix_usage_trigger"
AFTER UPDATE OF "points_per_month"
ON "public"."clients"
FOR EACH ROW WHEN (ROW.prepaid)
EXECUTE PROCEDURE "fix_prepaid_client_available_usage"();
psql is telling me this:
ERROR: missing FROM-clause entry for table "row"
LINE 1: ...r_month" ON "public"."clients" FOR EACH ROW WHEN (ROW.prepai...
Clearly I have no FROM clause there, but I'm not sure why I'd need one, nor where to put it.
That should be when (new.prepaid), per David's comment. You can access old and new in the when clause (as in the row before and after the update) much like table aliases. The error message is PG complaining that row is not a known table.
Two additional notes:
it might need to be when (old.prepaid or new.prepaid) if you want to manage billing plan switches -- or another two separate triggers. Conversely, when (old.prepaid and new.prepaid) if you do not, and someone might run database queries that might inadvertently fire the trigger and create undesirable state (add a unit test or two).
the function's name suggest something might be wrong further up in your code flow. You might want to fix that instead, by setting the available usage properly to begin with. Doing so might be more efficient, too.
I want to create a trigger, somehow like this:
CREATE TRIGGER foo
AFTER UPDATE OR INSERT ON bar
FOR EACH ROW EXECUTE PROCEDURE baz(NEW.id);
The part with NEW.id doesn't work. How can I send values from the changed row (id for instance) to the trigger-function.
The trigger function (procedure) knows NEW and OLD automatically. No need to pass those as parameters.
Read more in the chapter on Trigger Procedures in the manual:
When a PL/pgSQL function is called as a trigger, several special
variables are created automatically in the top-level block. They are:
NEW
Data type RECORD; variable holding the new database row for INSERT/UPDATE operations in row-level triggers. This variable is NULL
in statement-level triggers and for DELETE operations.