Trigger to update table column when new row is insert in postgresql? - postgresql

I want to write trigger to update table when new row is insert. I am using updatea Query like
UPDATE table SET
geom = ST_SetSRID(ST_MakePoint(longitude, latitude), 4326)

You need to use a BEFORE trigger and then assign the new value:
CREATE OR REPLACE FUNCTION function_update()
RETURNS trigger AS
$BODY$
BEGIN
new.geom := ST_SetSRID(ST_MakePoint(new.longitude, new.latitude), 4326);
RETURN new;
END;
$BODY$
LANGUAGE plpgsql;
This can only be done in a BEFORE trigger:
CREATE TRIGGER triggerinsert
BEFORE INSERT
ON rdpr
FOR EACH ROW
EXECUTE PROCEDURE function_update();

I Solved by writing trigger function like
CREATE OR REPLACE FUNCTION function_update()
RETURNS trigger AS
$BODY$
BEGIN
new.geom := ST_SetSRID(ST_MakePoint(new.longitude, new.latitude), 4326);
RETURN new;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
ALTER FUNCTION function_update()
OWNER TO postgres;
and i wrote trigger to update
CREATE TRIGGER triggerinsert
Before INSERT
ON rdpr
FOR EACH ROW
EXECUTE PROCEDURE function_update();

Related

Build a trigger that avoids to update the values of one column

I have a table in PostgretSQL. I want to build a trigger that avoids to update colb1 column. This column has five alternatives: Rea, Can, Loa, Mul, Alm. So the trigger doesn't let upload values from Rea to Can.
I've built this function but this is fail.
CREATE OR REPLACE FUNCTION example_trigger()
RETURNS trigger AS
$BODY$
BEGIN
new.colb1.tabl1 = 'Rea' := old.colb1.tabl1 = 'Can';
new.colb1.tabl1 = 'Can' := old.colb1.tabl1 = 'Rea';
RETURN new;
END
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
DROP TRIGGER IF EXISTS trigger_name ON table1;
CREATE TRIGGER trigger_name BEFORE UPDATE ON table1
FOR EACH ROW EXECUTE PROCEDURE example_trigger();
I edited my post with changes:
CREATE OR REPLACE FUNCTION example_trigger()
RETURNS TRIGGER AS
$$
BEGIN
NEW.colb1 := OLD.colb1;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER not_changes
BEFORE UPDATE
ON tabl1
FOR EACH ROW
EXECUTE PROCEDURE example_trigger();
It's not exactly that I want because I want that the values Loa, Mul and Alm can be update.
A slight modification of your function to stop the modification of colb1 from Rea or Can to Can or Rea.
CREATE OR REPLACE FUNCTION example_trigger()
RETURNS TRIGGER AS
$$
BEGIN
IF OLD.colb1 in ('Rea', Can') AND NEW.colb1 IN ('Rea', 'Can') THEN
NEW.colb1 := OLD.colb1;
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
This will not stop a user from using an intermediate UPDATE to change to one of Loa/Mul/Alm and then to either Rea or Can

How can I set the date when some row is created? I'm trying to use only Triggers and Functions at PostgreSQL

I have a table called recipes and my goal is for each time that I insert a new row, the column created_at, of this new row, automatically receives the value NOW().
I manage to do something like this on the column updated_at creating this function and trigger, and it's working fine.
CREATE OR REPLACE FUNCTION public.trigger_set_timestamp()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at = NOW();
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER set_timestamp
BEFORE UPDATE ON recipes
FOR EACH ROW
EXECUTE PROCEDURE trigger_set_timestamp();
But after I changed the code to set the created_at nothing happens and the Postgres doesn't point any errors.
CREATE OR REPLACE FUNCTION public.trigger_set_timestamp_created_at()
RETURNS trigger AS $$
BEGIN
NEW.created_at = NOW();
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER set_timestamp_created_at
AFTER INSERT ON recipes
FOR EACH ROW
EXECUTE PROCEDURE trigger_set_timestamp_created_at();

Trigger to update a column on update

I have written this function and this trigger:
CREATE OR REPLACE FUNCTION test4() RETURNS TRIGGER AS $BODY$
BEGIN
UPDATE "cf"
SET vol=(area*alt);
RETURN null;
END;
$BODY$
LANGUAGE plpgsql
trigger
CREATE TRIGGER trig_upd
AFTER OR UPDATE ON "cf"
FOR EACH ROW
EXECUTE PROCEDURE test4();
I have tested my function and it's ok. So I created the trigger, but I can't insert any value in the table "cf" because the system crashes.
If you want to update the value of vol for each modified row, don't use update, just assign the value. For this to work you also need to define the trigger as a before trigger:
CREATE OR REPLACE FUNCTION test4() RETURNS TRIGGER
AS
$BODY$
BEGIN
new.vol := new.area * new.alt;
RETURN new;
END;
$BODY$
LANGUAGE plpgsql;
CREATE TRIGGER trig_upd
BEFORE UPDATE ON "cf" --<< note the BEFORE!
FOR EACH ROW
EXECUTE PROCEDURE test4()

How to log delete queries on Postgresql?

I created a function which writes information about table deletions.
And another function which simply adds a trigger call after delete.
But I would like to store the whole row as string into my table.
According to Postgresql Documentation it should work by adding "OLD.*" into a text based column. But it fails telling me that I try to put too many columns into this table.
OLD is from type RECORD. And i want to have it in my text field like "value1,value2,value3" or it could be "colname:value,colname2:value". I dont care, I just want to see the row which has been deleted.
Another approach can be to log all delete queries from pg_stat_activity. But I don't know how to do that. Simply accessing pg_stat_activity every second would cause too much traffic I guess.
My table is simple:
create table delete_history (date timestamp, tablename varchar(100), data text);
This is my function:
CREATE or REPLACE FUNCTION ondelete() RETURNS TRIGGER AS $$
BEGIN
INSERT INTO delete_history VALUES (CURRENT_TIMESTAMP, TG_TABLE_NAME, OLD.*);
RETURN OLD;
END;
$$ LANGUAGE plpgsql;
This is my trigger:
CREATE OR REPLACE FUNCTION history_create_triggers() RETURNS void
AS $$
DECLARE
r RECORD;
BEGIN
FOR r IN SELECT table_name FROM information_schema.tables WHERE table_schema = 'public' AND table_type='BASE TABLE' LOOP
EXECUTE 'CREATE TRIGGER log_history AFTER DELETE ON public.' || r.table_name || ' FOR EACH ROW EXECUTE PROCEDURE ondelete();';
END LOOP;
END;
$$ LANGUAGE plpgsql;
You can convert type record into text:
CREATE or REPLACE FUNCTION ondelete() RETURNS TRIGGER AS $$
BEGIN
INSERT INTO delete_history VALUES (CURRENT_TIMESTAMP, TG_TABLE_NAME, OLD::text);
RETURN OLD;
END;
$$ LANGUAGE plpgsql;
sql fiddle demo
another approach could be converting your row into JSON with row_to_json function (if you have version 9.2):
CREATE or REPLACE FUNCTION ondelete() RETURNS TRIGGER AS $$
BEGIN
INSERT INTO delete_history VALUES (CURRENT_TIMESTAMP, TG_TABLE_NAME, row_to_json(OLD));
RETURN OLD;
END;
$$ LANGUAGE plpgsql;
sql fiddle demo
Another approach can be convert your data to hstore
CREATE or REPLACE FUNCTION ondelete() RETURNS TRIGGER AS $$
BEGIN
INSERT INTO delete_history VALUES (CURRENT_TIMESTAMP, TG_TABLE_NAME, hstore(OLD));
RETURN OLD;
END;
$$ LANGUAGE plpgsql;
I can't test it now - sqlfiddle is not allowing to use hstore.

Postgresql : insert record using trigger

CREATE TABLE users
(
id integer NOT NULL DEFAULT nextval('userseq'::regclass)
........
)
CREATE TABLE History
(
userid integer,
createdat timestamp with time zone
)
CREATE OR REPLACE FUNCTION recordcreatetime()
RETURNS trigger AS
$BODY$
BEGIN
NEW.createdAt = NOW();
RETURN NEW;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
User and History has one-one relationship. How i can insert new record in History table before creating new user.
CREATE OR REPLACE FUNCTION recordcreatetime()
RETURNS trigger
language plpgsql
AS $$
DECLARE
BEGIN
INSERT INTO History values(new.id,NOW() );
RETURN NEW;
END;
$$;
and write trigger statement as
CREATE TRIGGER user_hist
BEFORE INSERT ON users
FOR EACH ROW EXECUTE function recordcreatetime() ;