I'm using postgresql. These are the table involved in the trigger:
Pricing (title,publisher,period,offer,price)
The DB has 4 tables describing a magazine business.
The table above shows the title, publisher of the magazine, period (an option the subscribe to the magazine, in months (integer), offer (a string, like 'regular' or 'renew'), and price (integer).
The question:
Write a trigger that adds a new row in the pricing table.
If a new row is inserted with offer='regular', insert a new row, exactly the same BUT:
offer='renew' and a price discount of 10%.
Here my trigger, which doesn't work:
create or replace function offer_f() returns trigger as $$
begin
if(TG_OP='insert') then
if new.offer='regular' then
insert into pricing (title,pusblisher,offer,period, price)
values (new.title,new.publisher,"renew",new.period,new.price*0.9);
end if;
end if;
return new;
end;
$$
language plpgsql;
This is the trigger itself:
create trigger reduced_offer
after insert or update on pricing
for each row
execute procedure offer_f()
I really don't know what's wrong here, and I have tried replacing "after" with "before" in the trigger.
Thanks,
Alan
Related
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;
I'm trying to set an "after insert" trigger that executes a procedure. The procedure would take all inserted rows in table A, group them by a column and insert the result in a table B. I know about "new" variable but it gets inserted rows one by one. Is it possible to get all of them?
I think I can't use a for each row statement as I need to group rows depending on the "trackCode" variable, shared by different rows in tableA.
CREATE OR REPLACE PROCEDURE Public.my_procedure(**inserted rows in tableA?**)
LANGUAGE 'plpgsql'
AS $$
BEGIN
INSERT INTO Public."tableB" ("TrackCode", "count")
SELECT "TrackCode", count(*) as "count" FROM Public."tableA" --new inserted rows in this table
GROUP BY "vmsint"."TrackCode" ;
COMMIT;
END;
$$;
create trigger Public.my_trigger
after insert ON Public.tableA
execute procedure Public.my_procedure(**inserted rows in tableA?**)
Thank you!
You create a statement lever trigger, but do not attempt to pass parameters. Instead use the clause referencing new table as reference_table_name. In the trigger function you use the reference_table_name in place of the actual table name. Something like: (see demo)
create or replace function group_a_ais()
returns trigger
language 'plpgsql'
as $$
begin
insert into table_b(track_code, items)
select track_code, count(*)
from rows_inserted_to_a
group by track_code ;
return null;
end;
$$;
create trigger table_a_ais
after insert on table_a
referencing new table as rows_inserted_to_a
for each statement
execute function group_a_ais();
Do not attempt to commit in a trigger, it is a very bad id even if allowed. Suppose the insert to the main table is part of a larger transaction, which fails later in its process.
Be sure to refer to links provided by Adrian.
I have the requirement to move data from one table to another table when the value of one of the columns is updated. And I just want to move the updated row to the new table.
Below is my trigger that I have written. The issue with my code is, that it is moving all the data and not just the row which was updated. Can anyone give a suggestion?
create or replace function moveToAC1ControlHist()
returns trigger as $$
begin if NEW.file_status='CO'
then
insert into ac1_control_hist (file_status,identitifier)
(
select file_status,identitifier
from
ac1_control where new.FILE_STATUS = 'CO'
);
end if;
return new;
end;
$$ language plpgsql;
create TRIGGER AC1_CONTROL_TRIGGER AFTER update of file_status ON AC1_CONTROL
FOR EACH ROW when (new.file_status ='CO')EXECUTE PROCEDURE moveToAC1ControlHist();
I think the logic you want is:
create or replace function moveToAC1ControlHist()
returns trigger as
$$
begin
insert into ac1_control_hist (file_status,identitifier)
values (new.file_status, new.identitifier);
return null;
end;
$$ language plpgsql;
create trigger ac1_control_trigger
after update of file_status on ac1_control
for each row
when (new.file_status ='co')
execute function movetoac1controlhist()
;
Rationale:
you just want to copy (part of) the row being updated, so there is no need to select; you can access the values of the current row with new in a row-level trigger
the trigger definition filters on new file_status that is equal to 'CO', so there is no need for a if construct in the function
this is an after trigger, so you can just return null - the result is discarded anyway
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
i am new to trigger, is there a way to trigger input to databaseB.track conferenceid whenever there is a new record in databaseA.conference? this is what i did and is not working.
DELIMITER//
CREATE or replace TRIGGER insert_confer
after insert ON conference
for each row
begin
insertdatabaseb.Track(:new.conferenceid);
end;
/
DatabaseA Database B
Conference Track
-conferenceid -Trackid
-conferencename -Trackname
-conferencevenue -Conferenceid
The issue isn't the trigger per se but rather the syntax on the insert. Perhaps:
DELIMITER//
CREATE or replace TRIGGER insert_confer
after insert ON conference
for each row
begin
insert into databaseb.Track(conferenceid)
values (:new.conferenceid);
end//
DELIMITER ;