PostgreSQL simple trigger question - sql

trigger:
CREATE TRIGGER "tr_update_ts" BEFORE INSERT OR UPDATE
ON "public"."test" FOR EACH ROW
EXECUTE PROCEDURE "public"."update_ts"();
and the function is:
CREATE OR REPLACE FUNCTION "public"."update_ts" () RETURNS trigger AS
$body$
DECLARE
BEGIN
NEW.ts := now();
RETURN NEW;
END;
$body$
LANGUAGE 'plpgsql' VOLATILE CALLED ON NULL INPUT SECURITY INVOKER;
Why is this not working? No error thrown, but the ts is still null...

I tested your code and it works:
First, let's create table:
# create table test (x int4, ts timestamptz);
CREATE TABLE
Now, Let's add function:
# CREATE OR REPLACE FUNCTION "public"."update_ts" () RETURNS trigger AS
>> $body$
>> DECLARE
>> BEGIN
>> NEW.ts := now();
>> RETURN NEW;
>> END;
>> $body$
>> LANGUAGE 'plpgsql' VOLATILE CALLED ON NULL INPUT SECURITY INVOKER;
CREATE FUNCTION
And finally, add a trigger:
# CREATE TRIGGER "tr_update_ts" BEFORE INSERT OR UPDATE
>> ON "public"."test" FOR EACH ROW
>> EXECUTE PROCEDURE "public"."update_ts"();
CREATE TRIGGER
So, now, let's test ON INSERT part of it:
# insert into test (x) values (1);
INSERT 0 1
# select * from test;
x | ts
---+-------------------------------
1 | 2009-09-12 19:54:50.812139+02
(1 row)
Clearly it works.
Now, the update:
# update test set x = 2;
UPDATE 1
# select * from test;
x | ts
---+-------------------------------
2 | 2009-09-12 19:54:57.463933+02
(1 row)
ts has been changed. Clearly the code you shown works, so the error must be someplace else.
Show us "\d test" output from psql, and \df+ of the trigger function.

What is the full syntax of your create function? Here is the full syntax of the function that I created, and it is working as expected.
create function update_timestamp() RETURNS trigger AS $$
BEGIN
NEW.ts := now();
RETURN NEW;
END;
$$ language plpgsql;

Related

Functions(procedure)

I have many different queries (here is an example)
delete from dict.dct_task_type;
insert into dict.dct_task_type(id_task_type,nm_task_type)
SELECT * FROM dblink
('db',
$$ select id_dict, nm_dict from dict.d_dict where kd_dict_entity = 30 $$)
AS dct_task_type(id_task_type bigint,nm_task_type varchar);
delete from dict.dct_task_resolution;
insert into dict.dct_task_resolution (id_task_resolution,nm_task_resolution)
SELECT * FROM dblink
('db',
$$ select id_dict, nm_dict from dict.d_dict where kd_dict_entity = 32 $$)
AS dct_task_resolution(id_task_resolution bigint,nm_task_resolution varchar);
I want to do a job in time, for this I want to save the requests as procedures, how do I write them correctly?
DECLARE
variable_name datatype;
BEGIN
statements;
EXCEPTION
WHEN exception_name THEN
statements;
END;
or
CREATE OR REPLACE FUNCTION
Write an example with my values.
CREATE OR REPLACE FUNCTION dict.only_dict (
)
RETURNS void AS
$body$
BEGIN
delete from dict.dct_task_type;
insert into dict.dct_task_type(id_task_type,nm_task_type)
SELECT * FROM dblink
('ccrm_pp',
$$ select id_dict, nm_dict from dict.d_dict where kd_dict_entity = 30 $$)
AS dct_task_type(id_task_type bigint,nm_task_type varchar);
delete from dict.dct_task_resolution;
$body$
LANGUAGE 'plpgsql'
VOLATILE
CALLED ON NULL INPUT
SECURITY INVOKER
PARALLEL UNSAFE
COST 100;
ALTER FUNCTION dict.only_dict ()
OWNER TO mb_owner;

Correct SQL table alias syntax in trigger with if statement

So basically I'm trying to create a trigger that will update another table if an insert or update is located less than 1 meter of distance of an existing one.
It does not allow me to insert anything because the FROM clause is missing on the if statement and I'm not sure how to call it properly.
I got the following
CREATE TRIGGER access_node_aiu
AFTER INSERT OR UPDATE
ON schemab.table
FOR EACH ROW
EXECUTE PROCEDURE schemab.trigegr();
CREATE OR REPLACE FUNCTION schemab.trigger()
RETURNS trigger AS
$BODY$
BEGIN
if st_distance(new.geom, a.geom) < 1 then
INSERT INTO schemab.overlap
SELECT nextval('schemab.overlap_id_seq'::regclass), a.node_id, new.node_id, a.date, now(), st_distance(a.geom, new.geom), new.geom
FROM schemab.table a;
end if;
RETURN new;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
How to do this in postgresql?
Change IF into WHERE
CREATE OR REPLACE FUNCTION schemab.trigger()
RETURNS trigger AS
$BODY$
BEGIN
INSERT INTO schemab.overlap
SELECT nextval('schemab.overlap_id_seq'::regclass), a.node_id, new.node_id, a.date, now(), st_distance(a.geom, new.geom), new.geom
FROM schemab.table a
WHERE st_distance(new.geom, a.geom) < 1;
RETURN new;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;

Postgres trigger creation - ERROR: no language specified SQL state: 42P13

I am new to triggers. I am trying to create a trigger by following this link - http://www.postgresqltutorial.com/creating-first-trigger-postgresql/. But it gives some error. The code block and the error is given below.
Code block:
CREATE OR REPLACE FUNCTION log_last_name_changes()
RETURNS trigger AS
$BODY$
BEGIN
IF NEW.last_name <> OLD.last_name THEN
INSERT INTO employee_audits(employee_id,last_name,changed_on)
VALUES(OLD.id,OLD.last_name,now());
END IF;
RETURN NEW;
END;
$BODY$
And the error:
ERROR: no language specified
SQL state: 42P13
What can I try next?
Try this way:
CREATE OR REPLACE FUNCTION log_last_name_changes()
RETURNS trigger AS
$BODY$
BEGIN
IF NEW.last_name <> OLD.last_name THEN
INSERT INTO employee_audits(employee_id,last_name,changed_on)
VALUES(OLD.id,OLD.last_name,now());
END IF;
RETURN NEW;
END;
$BODY$
LANGUAGE plpgsql VOLATILE -- Says the function is implemented in the plpgsql language; VOLATILE says the function has side effects.
COST 100; -- Estimated execution cost of the function.
If arriving here because your function gave you the same error (like mine did).. here's an over-baked example of using a function to update the tweet on the bottom right "blurb" with "hello world".
Important note: language goes BEFORE the last semicolon (see below). This is easy to miss in the accepted solution.
id (serial)
pub_id (text)
tweet (text)
1
abc
hello world
2
def
blurb
-- Optional drop if replace fails below.
drop function if exists sync_tweets(text, text);
create or replace function sync_tweets(
src_pub_id text, -- function arguments
dst_pub_id text
) returns setof tweets as -- i.e. rows. int, text work too
$$
declare
src_id int; -- temp function variables (not args)
dest_id int;
src_tweet text;
begin
-- query result into a temp variable
src_id := (select id from tweets where pub_id = src_pub_id);
-- query result into a temp variable (another way)
select tweet into src_tweet from tweets where id = src_id;
dest_id := (select id from tweets where pub_id = dst_pub_id);
update tweets set tweet=src_tweet where id = dest_id;
return query -- i.e. rows, return 0 with return int above works too
select * from tweets where pub_id in (src_pub_id, dst_pub_id);
end
$$ language plpgsql; -- need the language to avoid ERROR 42P13
-- Run it!
select * from sync_tweets('abc', 'def');
/*
Outputs
__________________________________________________
| id (serial) | pub_id (text) | tweet (text) |
|---------------|-----------------|----------------|
| 1 | abc | hello world |
| 2 | def | blurb |
--------------------------------------------------
*/

Trigger Not Executing Yet It's Created

I have a trigger function I'm trying to have execute in Postgres.
It compiles and adds the trigger, however it does not insert the value into the table as I had hoped.
The function it uses looks like this:
CREATE OR REPLACE FUNCTION
calc_gnpDifference(n integer, o integer)
RETURNS NUMERIC AS $$
SELECT $1 ::numeric - $2::numeric AS gnpDifference;
$$ LANGUAGE SQL;
And the Trigger part:
CREATE OR REPLACE FUNCTION autoCalculate() RETURNS TRIGGER AS $$
BEGIN
IF NEW.gnp_old > NEW.gnp_old THEN
NEW.gnpDifference := calc_gnpDifference(NEW.gnp_old, NEW.gnp);
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
DROP TRIGGER insertDifference ON country;
CREATE TRIGGER insertDifference BEFORE INSERT ON country
FOR EACH ROW EXECUTE PROCEDURE autoCalculate();
However, when I insert data, the trigger does not update the gnpDifference field as I had hoped. Thoughts on why this might be happening?
Obviously this condition: IF NEW.gnp_old > NEW.gnp_old will never be true so the trigger will never have any effect.

CURRENT_DATE in postgresql triggers

I have before insert trigger in postgres
CREATE OR REPLACE FUNCTION add_requestdate() RETURNS TRIGGER AS $$
DECLARE
BEGIN
new.requestdate := now();
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER addrequestdate
BEFORE INSERT ON requests FOR EACH ROW EXECUTE PROCEDURE add_requestdate ();
But it doesn't work! I have solution that works...
CREATE OR REPLACE FUNCTION add_requestdate() RETURNS TRIGGER AS $$
DECLARE
BEGIN
UPDATE requests SET requestdate=now() WHERE id=NEW.id;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER addrequestdate
BEFORE INSERT ON requests FOR EACH ROW EXECUTE PROCEDURE add_requestdate ();
I have only one question. Why new.requestdate := now(); doesn't work?
it working - probably you have some other dependency - it strange, your workable solution cannot to work, because before trigger doesn't see a tuple in table, and if you use after trigger, then you start recursion..
postgres=# create table x(a int, b date, c timestamp);
CREATE TABLE
postgres=# create function fxx()
postgres-# returns trigger as $$
postgres$# begin
postgres$# new.b := now();
postgres$# new.c := now();
postgres$# return new;
postgres$# end;
postgres$# $$ language plpgsql;
CREATE FUNCTION
postgres=# create trigger xxxx before insert on x for each row execute procedure fxx();
CREATE TRIGGER
postgres=# insert into x(a) values(10);
INSERT 0 1
postgres=# insert into x(a) values(209);
INSERT 0 1
postgres=# select * from x;
a │ b │ c
─────┼────────────┼────────────────────────────
10 │ 2012-01-07 │ 2012-01-07 18:36:57.665283
209 │ 2012-01-07 │ 2012-01-07 18:37:00.853442
(2 rows)
so, you can use CURRENT_DATE instead now(), it is preferable solution.