In PostgreSQL I'm trying to make a database trigger on an INSERT that passes the primary key of the new row as the payload of a channel notification using NOTIFY
I'm having trouble wrapping my head around the correct usage age of the NEW variable in this context. No matter what I try seems to generate a syntax error.
Below is a simplified example of my use case.
CREATE OR REPLACE FUNCTION table_event_notify_function()
RETURNS trigger AS $$
BEGIN
NOTIFY table_event_notify, NEW.id;
return NULL;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER table_events_insert_trigger AFTER INSERT ON table_events EXECUTE PROCEDURE table_event_notify_function();
psycopg2.errors.SyntaxError: syntax error at or near "NEW"
The payload parameter for NOTIFY must be a constant. To provide a dynamic parameter, you need to use pg_notify()
perform pg_notifiy('table_event_notify', new.id::txt);
Related
I am trying to create my first trigger in postgres but I keep receiving this: [42883] ERROR: function clear_article_flag does not exist.
What I am trying to do is: when a new row is inserted on articles with a non 'automatic' author to set is_automatic flag to false for the specific id.
CREATE OR REPLACE FUNCTION clear_article_flag()
RETURNS trigger
LANGUAGE plpgsql AS
$$
BEGIN
update flags
set is_automatic = false where id= new.id;
return NEW;
END ;
$$;
CREATE TRIGGER maintain_dummy_flag
AFTER INSERT
ON articles
FOR EACH ROW
WHEN ( new.author not in ('automatic') )
EXECUTE PROCEDURE clear_article_flag();```
My mistake, being the first time when I've created a trigger and a sql function, I didn't know that first I should run the part that creates the function and then the trigger.
I created a table name Student in PostgreSQL and then I tried defining a trigger on that table but it's showing an error message in doing so.
Trigger Syntax:
CREATE TRIGGER bi_Student BEFORE INSERT ON Student as $$
FOR EACH ROW
BEGIN
raise notice 'Successfully inserted into table(%)', user;
end $$;
Table Creation Command:
create table Student(Stu_id int, Stu_Name text, Stu_Age int, Stu_address char(30));
Actually I tried to declare the execution statements directly inside the trigger only rather than calling any procedure/ function from the trigger which is working fine but I want to do in this way in PostgreSQL.
PostgreSQL doesn't support it. You need trigger function always.
As documented in the manual you need a trigger function
create function my_trigger_function()
returns trigger
as
$$
begin
raise notice 'Successfully inserted into table(%)', user;
return new; --<< important (see the manual for details)
end
$$
language plpgsql;
Not sure what you intend with the user parameter there, as that is not the table name, but the current database user. If you want to display the actual table name, you need to use TG_RELNAME instead - which is an implicit variable available in the trigger function.
And a trigger definition
CREATE TRIGGER bi_Student
BEFORE INSERT ON Student
FOR EACH ROW
execute function my_trigger_function();
This might be a stupid question but pardon me, I'm trying to convert one of my MariaDB database into a PostgreSQL database. Here I'm getting an error while executing this function.
I cannot find what's wrong here,
create function tg_prodcut_insert()
returns trigger as '
BEGIN
SET NEW.id = CONCAT(1, LPAD(INSERT INTO product_seq VALUES (NULL) returning id, 6, 0));
END;
' LANGUAGE 'plpgsql';
Error is pointing to the 1 in CONCAT method, The type of id I'm trying to SET is char(7)
EDIT
I also tried this, this won't work either,
create function tg_orders_insert()
returns trigger as '
BEGIN
INSERT INTO order_seq VALUES (NULL);
SET NEW.id = CONCAT('1', LPAD(LAST_INSERT_ID(), 6, 0));
END;
' LANGUAGE 'plpgsql';
Thanks in advance.
It seems you are trying to simulate some kind of sequence with that code by inserting into a table and then getting the auto_increment value from that.
This can be done much more efficiently using a sequence in Postgres.
The error you get also isn't caused by the concat() function but because you are using the wrong syntax.
Value assignment is done using := in PL/pgSQL.
And there is also no last_insert_id() function in Postgres. To get the next value from a sequence use nextval(), to get the most recently generated value, you can use lastval() but that's not necessary here.
create sequence product_id_seq;
create function tg_product_insert()
returns trigger as
$$
BEGIN
NEW.id := concat('ORD', to_char(nextval('product_id_seq'), 'FM00000000'));
return new;
END;
$$
LANGUAGE plpgsql;
you will need to create a before trigger for that to work:
create trigger product_seq_trigger
before insert on product
for each row
execute procedure tg_product_insert();
Online example
But it would be a lot more efficient to switch to a proper identity column instead and get rid of the trigger.
I have the following functions and trigger with sequence setup:
I want to create a function and trigger that anytime I add a new row to STRATEGY_SITES table, the 'SITE_NUM' field will have the new sequential number from SITENUM_SEQ. Schema name is gismgr.
I am getting the following error:Underlying DBMS error[Error:control reached end of trigger procedure without return Context: PL/pgSQL function process_sites_edit()(gismgr.strategy_sites)::SQLSTATE=2F005][gismgr.startegy_sites]
CREATE OR REPLACE FUNCTION process_sites_edit() RETURNS TRIGGER AS $SITE_EDIT_TRIGGER$
begin
new.SITE_NUM := nextval('gismgr.SITENUM_SEQ');
end;
$SITE_EDIT_TRIGGER$ LANGUAGE 'plpgsql';
create TRIGGER SITE_EDIT_TRIGGER
before insert or update on STRATEGY_SITES for each row
EXECUTE PROCEDURE process_strategy_sites_edit();
CREATE SEQUENCE gismgr."SITENUM_SEQ" owned by gismgr.strategy_Sites.site_num
INCREMENT 1
START 19080
MINVALUE 19080
MAXVALUE 9999999999999999
CACHE 20;
This seems to be an ORACLEism which is unnecessary in Postgres. Assuming your table already exsists then just
alter table *table_name* alter column site_num default nextval('gismgr.SITENUM_SEQ')
Also make sure the insert does not mention the site_num column. If you feel you must continue with the trigger approach the your trigger function needs to specify the return value.
CREATE OR REPLACE FUNCTION process_sites_edit()
RETURNS TRIGGER AS $SITE_EDIT_TRIGGER$
begin
new.SITE_NUM := nextval('gismgr.SITENUM_SEQ');
return new;
end;
$SITE_EDIT_TRIGGER$ LANGUAGE 'plpgsql';
I would also suggest you do not want to fire the trigger on updates. That will change the site number on any/every update of a given row Are there FK referencing it - they will not be updated the update would fail. Further the procedure executed must match the function name:
create TRIGGER SITE_EDIT_TRIGGER
before insert on STRATEGY_SITES for each row
EXECUTE PROCEDURE process_sites_edit();
I know that there is an initcap () function, which will perform a transformation for a 'string'. But I want to know how I can perform a trigger that executes this function before inserting a value in the column name into my table client. In other words how my function 'func ()' needs to be declared.
CREATE TRIGGER trigg
BEFORE INSERT
ON client
FOR EACH ROW
EXECUTE PROCEDURE func()
CREATE FUNCTION func()
returns trigger as
$BODY$
begin
**???**
end;
$BODY$ language plpgsql;
You can access the record before the change that triggered the trigger via the OLD pseudo record and after the change via the NEW pseudo record in your trigger function. You can also change the latter.
So to change the name of your client use
NEW.name := initcap(NEW.name);
RETURN NEW;
in your trigger function body.
For more information see 42.9. Trigger Procedures.