I am using postgresql and pgadmin and I am new to this. I have a table "Users" that has the following columns (Username, Name, Email, Phone, Discount, Password, token, serial, created_on, updated_on, points, reference).
I was trying to create a trigger for the table so that everytime a new insert occurs with an existing username in the reference field, the points of the used username will be incremented by 50. So there are two operations - updating the existing table, inserting the new values.
I tried creating a trigger function like this:
create or replace function points()
returns trigger as
$BODY$
BEGIN
if
new."Users"."reference" in (old."Users"."username")
then
Insert into "Users"(Username,Name,Email,Phone,Discount,Password,token,serial,created_on,updated_on,points,reference)
values(new.Username,new.Name,new.Email,new.Phone,new.Discount,new.Password,new.token,new.serial,new.created_on,new.updated_on,new.points,new.reference);
update "Users"
set old."Users"."points" = old."Users"."points" + 50
where "Users"."username" = (select "Users"."username" from "Users" where new."Users"."reference" in (old."Users"."username"));
end if;
RETURN new;
END;
$BODY$
language plpgsql;
and a trigger like this:
create trigger referece_points
after insert
on "Users"
for each row
execute procedure points();
But when I try to insert a new values in the "Users" table, I get the following error:
ERROR: missing FROM-clause entry for table "Users" LINE 1: SELECT new."Users"."reference" in (old."Users"."username") ^ Query: SELECT new."Users"."reference" in (old."Users"."username") CONTEXT: PL/pgSQL function points() line 2 at IF
New is composite variable of type that is related to table joined with trigger.
The code new."Users"."reference" has not any sense. You should to write just new."reference".
Related
Fire trigger on update of columnA or ColumnB or ColumnC
Set up the scene
begin;
create temp table account_details(email text primary key, username text, password text);
insert into account_details(email, username, password) values('a.com','b','c'),('b.com','d','e');
commit;
create function:
CREATE OR REPLACE FUNCTION notify_insert_account_details()
RETURNS trigger
LANGUAGE plpgsql AS
$$
BEGIN
RAISE NOTICE 'hello world';
END
$$;
create trigger:
CREATE TRIGGER trigger_update_account_details
AFTER UPDATE ON account_details
FOR EACH ROW
WHEN (OLD.email IS DISTINCT FROM NEW.email
OR OLD.username IS DISTINCT FROM NEW.username
OR OLD.password IS DISTINCT FROM NEW.password)
EXECUTE PROCEDURE notify_insert_account_details();
Trying to update:
update account_details set username = 'username1' where email = 'a.com';
The result: notify_insert_account_details() fired. but didn't execute the update clause.
NOTICE: hello world
ERROR: control reached end of trigger procedure without RETURN
CONTEXT: PL/pgSQL function notify_insert_account_details()
My question: how sophisticated this procedure/function notify_insert_account_details() Can become, let's say linked within 3 table. Can anyone showcase an example/demo?
I have the following code in postgresql:
CREATE OR REPLACE FUNCTION update_category() RETURNS trigger AS $newProduct$
BEGIN
UPDATE category SET product_count = product_count + 1 WHERE cat_id = NEW.cat_id;
INSERT INTO notification (content, type, p_id) VALUES('new product', 1, NEW.p_id);
RETURN NEW;
END;
$newProduct$ LANGUAGE plpgsql;
CREATE TRIGGER update_cat AFTER INSERT ON product
EXECUTE PROCEDURE update_category();
And after inserting a record into product I get the error:
[2017-03-20 16:05:05] [55000] ERROR: record "new" is not assigned yet
[2017-03-20 16:05:05] Detail: The tuple structure of a not-yet-assigned record is indeterminate.
[2017-03-20 16:05:05] Where: SQL statement "UPDATE category SET product_count = product_count + 1 WHERE cat_id = NEW.cat_id"
[2017-03-20 16:05:05] PL/pgSQL function update_category() line 3 at SQL statement
I've looked around for a solution, but I only find cases where the error is because
FOR EACH STATEMENT
is being used instead of
FOR EACH ROW
Seeing as I'm simply executing the procedure once, the solution doesn't apply in my case.
Thanks for your help!
The solution was indeed to add FOR EACH ROW:
CREATE TRIGGER update_cat AFTER INSERT ON product
FOR EACH ROW EXECUTE PROCEDURE update_category();
I assumed FOR EACH ROW meant calling the procedure once for each row in product, not for each row inserted.
I have this code, to add trigger for a View in my postgresql database
CREATE OR REPLACE FUNCTION changeCityProc() RETURNS TRIGGER AS $changeCity$
BEGIN
UPDATE vvs.tb_company SET city = "LAL" WHERE cardpresso.cardinfo.tb_company_city = vvs.tb_company.city;
RETURN null;
END;
$changeCity$ LANGUAGE plpgsql;
CREATE TRIGGER mytrigger
INSTEAD OF UPDATE ON
cardpresso.cardinfo FOR EACH ROW EXECUTE PROCEDURE changeCityProc();
pgAdmin says "syntax error at or near "INSTEAD""
Let's simplify this. First, the two schemas.
CREATE SCHEMA cardpresso;
CREATE SCHEMA vvs;
Next, the simplest possible table.
CREATE TABLE vvs.tb_company
(
city character varying(25)
);
INSERT INTO vvs.tb_company VALUES ('foo');
And a fairly useless view.
CREATE VIEW cardpresso.cardinfo AS
SELECT 'test' as tb_company_city UNION ALL
SELECT 'Orem' UNION ALL
SELECT 'Wibble'
;
Simplify the function. Warning: This will destructively update the table. Be careful if you copy stuff from this function into something headed for production.
CREATE OR REPLACE FUNCTION changecityproc()
RETURNS trigger AS
$BODY$
BEGIN
UPDATE vvs.tb_company SET city = 'bar';
RETURN null;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
Finally, the trigger.
CREATE TRIGGER mytrigger
INSTEAD OF UPDATE
ON cardpresso.cardinfo
FOR EACH ROW
EXECUTE PROCEDURE changecityproc();
Now, if we update the view, we'd expect all the rows in vvs.tb_company to change to 'bar'.
select * from vvs.tb_company;
city
--
foo
update cardpresso.cardinfo
set tb_company_city = 'wibble';
select * from vvs.tb_company;
city
--
bar
So it looks like the problem is in the UPDATE statement of your function.
UPDATE vvs.tb_company SET city = "LAL"
WHERE cardpresso.cardinfo.tb_company_city = vvs.tb_company.city;
I'm not certain what you intended that statement to do, but it's not valid in PostgreSQL, regardless of whether "LAL" is supposed to be a column name or a string literal. As a string literal, 'LAL', it will raise an error.
ERROR: missing FROM-clause entry for table "cardinfo"
LINE 2: WHERE cardpresso.cardinfo.tb_company_city = vvs.tb_compa...
I have to write a trigger to ensure unique entries in column account of table accounts:
create table accounts (id serial, account int4 default 0);
I tried to write my trigger like this:
create function x_6 () returns trigger as '
begin
IF row(new.account) is distinct from row(OLD.account) THEN
return NEW;
ELSE
raise notice '' Entries are not unique! '';
END IF;
end;
'
language 'plpgsql';
Or:
create function x_6 () returns trigger as '
begin
IF (new.account <> OLD.account) THEN
return NEW;
ELSE
raise notice '' Entries are not unique ! '';
END IF;
end;
'
language 'plpgsql';
And then
create trigger x_6t before insert on accounts for each row execute procedure x_6();
When I try to insert something:
insert into accounts(account) values (20);
I get an error in either case:
ERROR: record "old" is not assigned yet
DETAIL: The tuple structure of a not-yet-assigned record is indeterminate.
CONTEXT: PL/pgSQL function "x_6" line 3 at if
How can I fix it?
This is absolutely wrong way. You should not to use triggers for this purpose, you should to use unique indexes.
CREATE TABLE foo(a int PRIMARY KEY, b int);
-- column b has only unique values
CREATE UNIQUE INDEX ON foo(b);
Your code has more than one issue:
bad identifiers - konto instead account
it is table trigger - you has no any access to data there - PostgreSQL triggers are different than MSSQL
If you use row trigger, where there is possible access to record data, then OLD has different meaning than you expect. It is value of record before change - and this value is defined only for UPDATE or DELETE operations - and it is undefined for INSERT, because there previous value of record doesn't exist.
I am just started writing the PL/pgSQL Trigger function. I am having couple of tables called Student and Result. Student having the following columns. ID,name,subject,mark (ID is the primary key) and the Result table is having two columns like ID,Status
Whenever one record has added in the student table, I want to update the Result table by checking the mark in the Student table, If the mark entered is greater than 50 then one record should be inserted in the Result table with ID and Status = Pass and if it is less than 50 then status will be fail.
I have the following Trigger function to achieve this
CREATE OR REPLACE FUNCTION "UpdateResult"() RETURNS trigger AS $BODY$
BEGIN
IF NEW.mark < 50 THEN
INSERT INTO "Result" SELECT 92,'fail';
RETURN NEW;
ELSE
INSERT INTO "Result" SELECT 92,'pass';
RETURN NEW;
END IF;
END;
$BODY$
LANGUAGE 'plpgsql' VOLATILE STRICT SECURITY DEFINER
COST 100;
ALTER FUNCTION "UpdateResult"() OWNER TO postgres;
CREATE TRIGGER "Result"
AFTER INSERT
ON "Student"
FOR EACH ROW
EXECUTE PROCEDURE "UpdateResult"();
By this function trigger has worked as expected since I have hard coded the primary key value.
But When I modify the SQL inside Trigger function like the following
INSERT INTO "Result" SELECT NEW.ID,'fail'; (or)
INSERT INTO "Result" SELECT NEW.ID,'pass';
It is throwing error like
> ***Record "new" has no field "id" Context : PL/pgSQL function
> "UpdateResult" line 3 at SQL statement***
Means it is able to take the values of non primary key values from NEW variable not the primary key value. Can any one please tell me is there a restriction in PL/pgSQL or Am I doing anything wrong !
Just a hint: why are you using quoted names? When doing this, you have to care about capitalisation.
See if this works:
CREATE OR REPLACE FUNCTION UpdateResult() RETURNS trigger AS $BODY$
BEGIN
IF NEW.mark < 50 THEN
INSERT INTO result (id, status) values (92,'fail');
RETURN NEW;
ELSE
INSERT INTO result (id, status) values (92,'pass');
RETURN NEW;
END IF;
END;
$BODY$
LANGUAGE 'plpgsql' VOLATILE STRICT SECURITY DEFINER
COST 100;
ALTER FUNCTION UpdateResult() OWNER TO postgres;
CREATE TRIGGER Result
AFTER INSERT
ON Student
FOR EACH ROW
EXECUTE PROCEDURE UpdateResult();