Updating current timestamp of multiple tables through single trigger function - postgresql

I have 2 tables created :- Table Banks and Branch. Both the tables have column last_updated(which means when was the record last updated.) I have created after update trigger for each row on both the tables. The trigger and trigger function looks like below :-
create trigger banks_upd_trg
after update of phone_no
on Banks
FOR EACH ROW
EXECUTE PROCEDURE bankdetails_upd();
create trigger branch_upd_trg
after update of email_address
on Branch
FOR EACH ROW
EXECUTE PROCEDURE bankdetails_upd();
create or replace FUNCTION bankdetails_upd()
RETURNS trigger AS
$BODY$
BEGIN
EXECUTE format('update %I.%I SET last_updated=current_timestamp where id=new.id',TG_SHEMA_NAME,TG_TABLE_NAME)
RETURN NEW;
END;
$BODY$
LANGUAGE plpgsql
The trigger is getting executed successfully but isn't working at the time of updating phone_no and email_address column in Banks and Branch table respectively.

No need for dynamic SQL or an UPDATE statement.
Use a before trigger and assign the value to the NEW record.
create or replace FUNCTION bankdetails_upd()
RETURNS trigger AS
$BODY$
BEGIN
new.last_updated := current_timestamp;
RETURN NEW;
END;
$BODY$
LANGUAGE plpgsql;
create trigger banks_upd_trg
BEFORE update of phone_no
on Banks
FOR EACH ROW
EXECUTE PROCEDURE bankdetails_upd();
create trigger branch_upd_trg
BEFORE update of email_address
on Branch
FOR EACH ROW
EXECUTE PROCEDURE bankdetails_upd();

Related

Postgres update column value to time.Now()

I need to update column paid_at to time.Now() on table orders when column status is updated to paid is it possible to create a trigger on postgres? they are all in a same table orders
is it possible to create a trigger on postgres
Yes, that's possible.
As documented in the manual you need a trigger function first:
create function update_paid_at()
returns trigger
as
$$
begin
new.paid_at := now();
return new;
end;
$$
language plpglsql;
Then you need a trigger definition:
create trigger update_orders_trigger
before update on orders
for each row
when (new.status = 'paid' and new.status <> old.status)
execute procedure update_paid_at();
The trigger only fires if the status is changed to 'paid' and then sets the value of paid_at column.

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();

PostgreSql Trigger does not work when called 'insert'

The code below is my code to create trigger function to change column "pass".
create or replace function change_pass()
returns trigger as
$$
begin
NEW.pass := 'XXXXXXXXX';
return NEW;
end
$$
language plpgsql;
create trigger change_pass
AFTER insert or update on "D_ACCOUNT"
for each row execute procedure change_pass();
When i called insert, i did not see any changes in my data.
Can anyone explain to me where i was wrong?
You need a BEFORE trigger to change values in the NEW record:
create trigger change_pass
BEFORE insert or update on "D_ACCOUNT"
for each row execute procedure change_pass();

Triger update function when column updates in Postgres

I have users table with columns status_id (int), additional_status(int) and status_changed(DATE).
I want to autoupdate status_changed field every time when status_id or additional_status changes.
Here is what I have by now:
CREATE OR REPLACE FUNCTION update_status_changed()
RETURNS TRIGGER
AS $$
BEGIN
NEW.status_changed := CURRENT_TIMESTAMP;
RETURN NEW;
END $$ LANGUAGE plpgsql;
CREATE TRIGGER set_update_status_changed
AFTER INSERT OR UPDATE OF status_id, additional_status ON users
FOR EACH ROW
EXECUTE PROCEDURE update_status_changed();
I'm not sure if the syntax is correct. When I change my status_id from phpPgAdmin - status_changed stays NULL. What am I'm missing?, help pls.

PostgreSQL triggers and temporary table

I have created an before update and after update trigger on a postgresql db table.
There is a requirement to preserve historical record and at the same time create a new record for the said data. Old record is to be marked as archived.
I was planning on using temporary table to keep track of the NEW values and reset the NEW values such that it is marked as archived.
In my after update trigger I would read the data from the temporary table, and create a brand new active record.
My problem is temporary table created in before update trigger is not visible to after update trigger. Moreover I cannot even pass on any argument (of type record) to the after update trigger as it is not allowed.
I have already achieved the desired result in Oracle db, using Global Temporary table, but having a tough time in PostgreSQL.
Here is the sample code for before update trigger function:
CREATE OR REPLACE FUNCTION trigger_fct_trig_trk_beforeupdate()
RETURNS trigger AS
$BODY$
DECLARE
some variable declarations;
BEGIN
Drop table IF EXISTS track_tmp_test;
CREATE TEMPORARY TABLE track_tmp_test(
...
);
Insert into track_tmp_test (........)
values(NEW., NEW..., NEW.., NEW...);
NEW... := OLD...;
NEW... := OLD.... ;
NEW... := OLD...;
Mark the NEW.status : = 'archived';
RETURN NEW;
END
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
CREATE TRIGGER trig_trk_test_beforeupdate
BEFORE UPDATE ON test
FOR EACH ROW EXECUTE PROCEDURE trigger_fct_trig_trk_beforeupdate() ;
NOW the after UPDATE trigger function:
CREATE OR REPLACE FUNCTION trigger_fct_trg_trk_afterupdate()
RETURNS trigger AS
$BODY$
DECLARE
some variables;
-- insert into original table the data from temporary that was inserted in before update trigger
INSERT into TEST (....)
select ....
from track_tmp_test ;
-- delete data from temporary table after insert
delete from track_tmp_test ;
EXCEPTION
WHEN OTHERS THEN
-- Consider logging the error and then re-raise
RAISE;
RETURN NEW;
END
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
Is there a way that after update trigger can access the temporary table created in before update trigger function?
I cannot have a permanent table hold he values, as trigger can be fired by many users updating the data in the table.
There is no problem with access to temporary table from triggers, and following code working without issue (on PostgreSQL 9.4):
CREATE OR REPLACE FUNCTION public.f1()
RETURNS trigger
LANGUAGE plpgsql
AS $function$
begin
drop table if exists bubu;
create temp table bubu(a int);
insert into bubu values(10);
return new;
end
$function$
CREATE OR REPLACE FUNCTION public.f2()
RETURNS trigger
LANGUAGE plpgsql
AS $function$
declare r record;
begin
for r in select * from bubu
loop
raise notice '%', r;
end loop;
return null;
end
$function$
create trigger xx
before insert on omega
for each row execute procedure f1();
create trigger yy
after insert on omega
for each row execute procedure f2();
postgres=# insert into omega values(333);
NOTICE: (10)
INSERT 0 1
So I am sure, so your problem will not be in access to temporary tables. It works well. There can be a issue on some 8.2, 8.3 and older with invalid plans due reference on dropped objects. Isn't it your problem?
I can say, so your design is wrong - there is not any reason, why you have to use a temp table. Same job you can do in after trigger. Any operations inside triggers should be fast, pretty fast. Dropping or creating temporary table is not fast operation.
If you have a older PostgreSQL release, you have not to drop temp table every. You should to delete content only. See a article http://postgres.cz/wiki/Automatic_execution_plan_caching_in_PL/pgSQL
The temporary table should be visible as #Pavel explains, but that's not the main issue here.
Your approach might make sense in Oracle with a global temporary table. But the posted Postgres code does not.
The trigger is fired for each row. You would (drop and) create a temp table for every row, and call another trigger, just to do what you could easily do in one trigger directly.
Instead, to keep the old row and set it to archived, plus INSERT a copy of the NEW row:
Demo table:
CREATE TEMP TABLE test (id int, txt text, archived bool DEFAULT FALSE);
Trigger func:
CREATE OR REPLACE FUNCTION trg_test_beforeupdate()
RETURNS trigger AS
$func$
BEGIN
INSERT INTO test SELECT (NEW).*; -- insert a copy of the NEW row
SELECT (OLD).* INTO NEW; -- revert row to previous state
NEW.archived = TRUE; -- just set it to "archived"
RETURN NEW;
END
$func$ LANGUAGE plpgsql;
Trigger:
CREATE TRIGGER beforeupdate
BEFORE UPDATE ON test
FOR EACH ROW EXECUTE PROCEDURE trg_test_beforeupdate();
Test:
INSERT INTO test VALUES (1, 'foo'), (2, 'bar');
UPDATE test SET txt = 'baz' WHERE id = 1;
SELECT * FROM test;
Works.