Update error in postgres SQL - sql

CREATE TRIGGER INSERT_salesorderdetail
before insert on salesorderdetail
for each row
UPDATE customer
set number_of_items=IFNULL(number_of_items,0)+1
where new.customerid=customer.customerid;
I have 2 tables salesorderdetail and customer and i want each time i inserts a new item in salesorderdetail to update my columne in customer the number_of_items but for some reason i get a syntax error in update.

This might help you:
CREATE OR REPLACE FUNCTION update_customer()
RETURNS trigger AS
$BODY$
-- update ur table here
RETURN NULL;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
ALTER FUNCTION update_customer()
OWNER TO db_name;
Now create trigger as:
CREATE TRIGGER INSERT_salesorderdetail
before insert on salesorderdetail
for each row execute procedure update_customer();

Related

Search in 3 tables using PL/pgSQL functions and triggers

I am new to SQL and still learning functions and triggers.
I have 3 tables:
PRODUCTS_BOUGHT
CUSTOMER
DATE
PRODUCTS
3FG
2022-12-15
25
4HZ
2022-12-18
30
PRODUCTS_PRICE:
DATE
TYPE
PRICE
2022-12-15
A
125$
2022-12-18
B
147$
CUSTOMERS_REGISTER:
CUSTOMER
TYPE
3FG
A
4HZ
B
I need to add a column "COST" in the REF table with a value obtained using: COST = PRICE * PRODUCTS. But the function needs to check that the price is applied based on the type of product purchased by the customer in that certain date to obtain something like this:
PRODUCTS_BOUGHT
CUSTOMER
DATE
PRODUCTS
COST
3FG
2022-12-15
25
3125
4HZ
2022-12-18
30
4410
I need to use something like the following:
ALTER TABLE products_bought
ADD COLUMN cost;
CREATE OR REPLACE FUNCTION calc_cost()
RETURNS TRIGGER AS $$
BEGIN
END;
$$ LANGUAGE plpgsql;
CREATE OR REPLACE TRIGGER cost_trigger
BEFORE INSERT OR UPDATE ON products_bought
FOR EACH ROW
EXECUTE FUNCTION calc_cost();
I have been trying creating the column first and then adding the value like this:
ALTER TABLE products_bought
ADD COLUMN cost;
CREATE OR REPLACE FUNCTION calc_cost()
RETURNS TRIGGER AS $$
BEGIN
SELECT(products_bought.products * products_price.price) INTO cost
FROM products_bought, products_price, customers_register
WHERE products_bought.rf_date = products_price.fp_date AND
customers_register.type = customers_register.type;
RETURN cost;
END;
$$ LANGUAGE plpgsql;
CREATE OR REPLACE TRIGGER cost_trigger
BEFORE INSERT OR UPDATE ON products_bought
FOR EACH ROW
EXECUTE FUNCTION calc_cost();
Selecting from the table products_bought in your trigger function looks like a misunderstanding. The trigger is fired BEFORE INSERT OR UPDATE ON products_bought, so just work with the special NEW record. And make sure you also RETRUN NEW;:
CREATE OR REPLACE FUNCTION calc_cost()
RETURNS trigger
LANGUAGE plpgsql AS
$func$
BEGIN
SELECT INTO NEW.cost
NEW.products * p.price
FROM products_price p
WHERE p.fp_date = NEW.rf_date;
RETURN NEW;
END
$func$;
This only makes sense if there is a single matching row in table products_price. If there can be more, you have to define which row to pick. If there is none, cost will not be assigned.
I also removed the table customers_register from the query, since it didn't seem to do anything useful (unless you wanted to nullify cost if there is no related row in that table, which I doubt.)
Related:
PostgreSQL Update trigger
The returning trigger function should return the NEW instead of only the column affected.
notice that the insert into is also beign inserted at the NEW.cost value.
You can look here : PostgreSQLTriggers for trigger default values like NEW , OLD from the row it is beign edited.
CREATE OR REPLACE FUNCTION calc_cost()
RETURNS TRIGGER AS $$
BEGIN
SELECT(products_bought.products * products_price.price) INTO NEW.cost
FROM products_bought, products_price, customers_register
WHERE products_bought.rf_date = products_price.fp_date AND
customers_register.type = customers_register.type;
RETURN NEW.*;
END;
$$ LANGUAGE plpgsql;

Update sum with trigger

I want to sum basket item price values and insert it into a payment as total price. I am trying to use a trigger for this but I am getting error near SET total_price =. Error msg: Expected expression, got 'select'. How do I deal with this?
CREATE FUNCTION make_sum() RETURNS TRIGGER
AS $$
BEGIN
UPDATE payment
SET total_price = select sum(price) from basket where basket_id = new.basket_id;
RETURN NULL;
END;$$ LANGUAGE plpgsql;
CREATE TRIGGER make_sum AFTER INSERT ON basket FOR EACH ROW EXECUTE make_sum()
Here is the updated version. I have made the following changes to your script:
Put the select in your update statement within parentheses
Added the keyword 'PROCEDURE' in your trigger definition.
CREATE FUNCTION make_sum() RETURNS TRIGGER
AS $$
BEGIN
UPDATE payment
SET total_price = (select sum(price) from basket where basket_id = new.basket_id);
RETURN NULL;
END;$$ LANGUAGE plpgsql;
CREATE TRIGGER make_sum
AFTER INSERT ON basket FOR EACH ROW EXECUTE PROCEDURE make_sum();

Update another table through a trigger where new value is the result of a SELECT query

I have these tables:
Users
Skills (name - string, count - integer)
Has_skills (skill_id - skills.id, user_id users.id)
Has_skills is a many to many table between the first two through these FK:
user_id (users.id) and skill_id (skills.id).
What I want to do is update the count column inside skills when a new row is inserted into has_skills. I want to do this through an update trigger on table has_skills. The new value for count I will get through a select query:
SELECT COUNT(*) AS cnt FROM skills
JOIN has_skills hs ON skills.id = hs.skill_id
WHERE hs.skill_id = 1;
The ID above is hardcoded (1), but it works.
I also tested this code in isolation, and it works (although hardcoded, as well):
UPDATE skills
SET count = subquery.cnt
FROM (
SELECT COUNT(*) AS cnt FROM skills
JOIN has_skills hs ON skills.id = hs.skill_id
WHERE hs.skill_id = 1
) AS subquery
WHERE skills.id = 1;
RETURN NEW;
Alright, so here's probably where the problem is. Below is the trigger function and also the trigger itself.
Function:
CREATE OR REPLACE FUNCTION update_skill_count() RETURNS trigger AS
$func$
BEGIN
UPDATE skills
SET count = subquery.cnt
FROM (
SELECT COUNT(*) AS cnt FROM skills
JOIN has_skills hs ON skills.id = hs.skill_id
WHERE hs.skill_id = NEW.skill_id
) AS subquery
WHERE skills.id = NEW.skill_id;
RETURN NEW;
END;
$func$ LANGUAGE plpgsql;
Trigger:
CREATE TRIGGER on_has_skills_insert
AFTER INSERT ON has_skills
FOR EACH ROW
EXECUTE PROCEDURE update_skill_count();
I successfully create the function and trigger, but when I insert new data into has_skills, it doesn't change the count column inside skills. What could be the problem?
There's no need for a select in the trigger function at all. The key for the skill table is directly available in new.skill_id so just use it directly:
-- trigger function and trigger
create or replace function update_skill_count()
returns trigger
as $func$
begin
update skills sk
set count = count+1
where sk.skill_id = new.skill_id;
return new;
end;
$func$ language plpgsql;
create trigger on_has_skills_insert
after insert on has_skills
for each row
execute procedure update_skill_count();
I'm not much familiar with postgresql, but having understanding of Oracle and SQL Server, this looks to be a mutating trigger problem, which is: Trying to read from or write into the same table within a row level trigger on which the trigger is placed.
One of the ways to get rid of mutating trigger/table problem can be changing the row level trigger to a statement level trigger and changing the function accordingly. Here is a psudo code you can try out (not providing the exact tested code as I do not have Postgresql installed):
Function:
CREATE OR REPLACE FUNCTION update_skill_count() RETURNS trigger AS
$func$
BEGIN
UPDATE skills
SET count = subquery.cnt
FROM (
SELECT hs.skill_id, COUNT(*) AS cnt
FROM new_table hs
GROUP BY hs.skill_id
) AS subquery
WHERE skills.id = subquery.skill_id;
RETURN NULL;
END;
$func$ LANGUAGE plpgsql;
Trigger:
CREATE TRIGGER on_has_skills_insert
AFTER INSERT ON has_skills
REFERENCING NEW TABLE AS new_table
FOR EACH STATEMENT EXECUTE PROCEDURE update_skill_count();

How to print NEW value with trigger Postgres

I want to create trigger for Insert operation, and procedure that prints inserted value.
CREATE TRIGGER added_product_info_trigger
BEFORE INSERT
ON products
EXECUTE PROCEDURE added_product_info();
And my procedure
CREATE OR REPLACE FUNCTION added_product_info()
RETURNS trigger
AS
$$
(Select p.productname, s.companyname from products as p, suppliers as s
where p.supplierid = s.supplierid)
$$ LANGUAGE SQL;
How can I print my inserted value?
Sql functions cannot return trigger. You probably wanted to write a plpgsql function.
A trigger function cannot generate any output (like results of a select query).
You can use raise notice to pass some results to the client program:
create or replace function added_product_info()
returns trigger as $$
declare
company text;
begin
select companyname
from suppliers
where supplierid = new.supplierid
into company;
raise notice 'inserted: "%" supplied by "%"', new.productname, company;
return new;
end;
$$ language plpgsql;
The record new is visible in a trigger function only if the trigger is declared for each row
(default is for each statement when records new and old are not accessible):
create trigger added_product_info_trigger
before insert on products
for each row
execute procedure added_product_info();
If a trigger is before insert for each row it must return new.
Note that the client must be ready to get and process the notice.
If you run the query in the standard psql shell program, you ll get:
insert into products values ('some product', 1);
NOTICE: inserted: "some product" supplied by "company"
INSERT 0 1
Read:
Overview of Trigger Behavior
Visibility of Data Changes
Trigger Procedures

Trigger to delete past records in postgresql

I want only to maintain present 1 month records log details. need to delete past record log details.I tried this code however could not work this,
create sequence userseq1;
CREATE TABLE users
( id integer NOT NULL DEFAULT nextval('userseq1'::regclass)
);
INSERT INTO users VALUES(126);
CREATE TABLE History
( userid integer
, createdate timestamp
);
CREATE OR REPLACE FUNCTION recordcreatetime() RETURNS trigger language plpgsql
AS $$
DECLARE
BEGIN
INSERT INTO History values(new.id,NOW() );
RETURN NEW;
END;
$$;
CREATE TRIGGER user_hist
BEFORE INSERT ON users
FOR EACH ROW
EXECUTE procedure recordcreatetime();
However it is working to insert values sequencing one by one adding.I want to delete the previous 1 month record Log details.I tried this below code and it is not working
CREATE OR REPLACE FUNCTION trf_keep_row_number_steady()
RETURNS TRIGGER AS
$body$
DECLARE
BEGIN
IF (SELECT count(createdate) FROM history) > rownum_limit
THEN
DELETE FROM history
WHERE createdate = (SELECT min(createdate) FROM history);
END IF;
END;
$body$
LANGUAGE plpgsql;
CREATE TRIGGER tr_keep_row_number_steady
AFTER INSERT ON history
FOR EACH ROW EXECUTE PROCEDURE trf_keep_row_number_steady();
I can see in your second code block, you have a trigger on history table and you are trying to DELETE FROM history in that same trigger.
Insert / Update / Delete on a table through a trigger on the same table is not allowed. Please think of some other alternative, e.g., running a separate DELETE statement for the required cleanup of rows before or after your main INSERT statement.