postgresql triggers after update - postgresql

The following function ,update_sessioninfo(), should only update changed columns. The New.* columns are being updated to some incorrect values after running:
update freeradius.radacct set acctsessiontime=25 where radacctid=3;
function
CREATE OR REPLACE FUNCTION update_sessioninfo() RETURNS trigger AS $radacct_update$
BEGIN
-- update the updated records
update freeradius.day_guiding_usage set acctstoptime=New.acctstoptime,acctsessiontime=New.acctsessiontime,connectinfo_start=New.connectinfo_start,connectinfo_stop=New.connectinfo_stop,acctinputoctets=New.acctinputoctets,acctoutputoctets=New.acctoutputoctets,acctterminatecause=New.acctterminatecause where acctsessionid=Old.acctsessionid;
RETURN NULL;
END;
$radacct_update$ LANGUAGE plpgsql;
The trigger is below
CREATE TRIGGER radacct_update AFTER UPDATE ON freeradius.radacct
FOR EACH ROW
WHEN (OLD.* IS DISTINCT FROM NEW.*)
EXECUTE procedure update_sessioninfo();

WHEN (OLD.* IS DISTINCT FROM NEW.*) means that there's something changed => old row is different from new row, but when update happens it will update all columns of your table.
See examples and documentation here: http://www.postgresql.org/docs/9.2/static/sql-createtrigger.html

Related

How to exclude columns which passed to procedure by trigger FOR EACH ROW in PostgreSQL, or at least exclude them thereafter

I have issue with creating PostgreSQL triggers
I have rigger executing amendments to table on FOR EACH ROW basis, but i need to process all columns in these rows except one.
I tried to find solution how prevent passing one of columns to procedure, but as i understand it's done automatically and can not be interfered.
OLD and NEW variables with old and new rows passed to procedure and i was searching how remove columns from OLD/NEW for further processing and failed so far
I have simple table1 with columns:
name
number
description
I have following trigger
CREATE TRIGGER table1_trigger
AFTER INSERT OR UPDATE OR DELETE ON table1
FOR EACH ROW EXECUTE PROCEDURE trigger_proc();
and following procedure
CREATE OR REPLACE FUNCTION trigger_proc() RETURNS TRIGGER AS
$$
DECLARE
old_v jsonb;
new_v jsonb;
BEGIN
old_v = json_strip_nulls(row_to_json(OLD));
new_v = json_strip_nulls(row_to_json(NEW));
END;
$$ LANGUAGE plpgsql;
After executing for example:
insert into table1 (name, number, description)
values ('name', 1, 'useless text to vanish')
I need column "description" either to be excluded
at stage passing to procedure "FOR EACH ROW EXECUTE PROCEDURE trigger_proc()"
or to be removed from OLD/NEW in procedure
or OLD/NEW data to be copied to some new variables with RECORD type, but of course without "description" column
or any other ways where old_v and new_v will not contain data from this column!
Thanks in advance for any help!

UPDATE ANOTHER COLUMN IN AFTER UPDATE TRIGGER

I have a table with three columns: id, date and dateDekete
I try to execute an update on the column dateDelete after an update on another column (column date) using a AFTER UPDATE TRIGGER.
The code that I use to create my trigger is the following:
CREATE OR REPLACE FUNCTION update_delete_date_allocation()
RETURNS trigger LANGUAGE plpgsql AS $body$
BEGIN
NEW."dateDelete" := NEW.date + 1;
RETURN NEW;
END;
$body$;
CREATE TRIGGER delete_date_allocation_trg
AFTER INSERT OR UPDATE ON client.client_portfolio_allocation
FOR EACH ROW
EXECUTE PROCEDURE update_delete_date_allocation();
Although the code executes fine with no error message, the latter column that I try to update does not change.
I was wondering if it's possible to do this. AND if so, what should I change in my code?
I am using Postgres 11.5.
you can't change the new record in an AFTER trigger, you need to declare your trigger as a BEFORE trigger:
CREATE TRIGGER delete_date_allocation_trg
BEFORE INSERT OR UPDATE ON client.client_portfolio_allocation
FOR EACH ROW
EXECUTE PROCEDURE update_delete_date_allocation();

Changing the value of multiple columns in a BEFORE INSERT trigger in Postgresql

I have a table, on which I want to update multiple columns when a new row is inserted. My current trigger, which only updates a single column, looks like the below (simplified):
CREATE OR REPLACE FUNCTION func_only_updates_one_column()
RETURNS trigger AS
$BODY$
BEGIN
NEW.one_column := (SELECT rslt.one_column FROM
(SELECT one_column, two_column, three_column, more_column
FROM NEW
JOIN a_very_complicated_query avcq
ON avcq.one_column = NEW.one_column
AND avcq.two_column = NEW.two_column) rslt;
RETURN NEW;
END
$BODY$
LANGUAGE 'plpgsql';
CREATE TRIGGER trig_update_table BEFORE INSERT on target_table
FOR EACH ROW EXECUTE PROCEDURE func_only_updates_one_column();
I could create another trigger for my other column with the same logic, or run the query multiple times, but I don't want to run a SELECT from a_very_complicated_query multiple times - it's quite expensive as-is, and my application depends on this query being fast.
How can I update multiple columns in a BEFORE INSERT trigger with a single subquery referring to the NEW row? I only want to run the SQL once. I am using Postgresql 11.
That would simply work like this:
SELECT rslt.one_column,
rslt.two_column,
...
INTO NEW.one_column,
NEW.two_column,
...
FROM /* your complicated query */

postgresSQL How to apply trigger only on updated row?

I'm trying to create a function + trigger that will update my "modif" attribut to current date when there is an update or insert on my table called "nada".
the code work well but all the rows are affected.I only want the current date on the rows that were updated.
Any idea ?
This is my code so far:
CREATE OR REPLACE FUNCTION public.maj_modif()
RETURNS "trigger" AS
$BODY$
BEGIN
NEW.modif:= (SELECT current_date);
RETURN NEW;
END;
$BODY$
LANGUAGE plpgsql;
DROP TRIGGER IF EXISTS maj_modif ON public.nada;
CREATE TRIGGER maj_modif BEFORE INSERT OR UPDATE ON public.nada
FOR EACH ROW
EXECUTE PROCEDURE public.maj_modif();
If I try the same code without "FOR EACH ROW" in the trigger I get this erreur: « new » is not affected yet (...) The structure of the registration line is not yet determined.
I assume that you only want the trigger to fire if any columns were actually changed.
That can be done with
CREATE TRIGGER maj_modif BEFORE UPDATE ON public.nada
FOR EACH ROW
WHEN OLD <> NEW
EXECUTE PROCEDURE public.maj_modif();
That only works for UPDATE, because on INSERT OLD is not defined. Define the INSERT trigger without the WHEN clause.

How to create a Trigger in PostgreSql?

TRIGEER-->To get a column value from one table to other table when i insert values?
I am having two tables(customer_details and loan_balance).
What i need is, I must get the column (custid)of customer_details table to the loan_balance table when i insert the data into the loan_balance table.
This is the full set up of my query : SQL FIDDLE
So i need a trigger to be raised and the data should be updated automatically without dynamic insertion of custid.
Postgres has an unconventional way of creating triggers:
create a function that returns type trigger and return the NEW row record
create a trigger that executes the function
Here's the code you need:
CREATE FUNCTION synch_custid_proc()
RETURNS trigger AS $$
BEGIN
NEW.custid = (
select max(custid)
from customer_details
where creditid = NEW.creditid
);
RETURN NEW;
END;
$$ LANGUAGE plpgsql
CREATE TRIGGER synch_custid_trig
BEFORE INSERT ON loan_amount
FOR EACH ROW
EXECUTE PROCEDURE synch_custid_proc();
I chosen to select max(custid) rather than simply custid when finding the value in case there are multiple rows that match. You might have to adjust this logic to suit your data.
See a live demo on SQLFiddle