I try to work with trigger here.
I have a relation like this :
salary(salaryid, userid, netsalary, reward, totalsalary)
So I want to update totalsalary everytime I insert and update (netsalary or reward), it will recount : totalsalary = netsalary + reward.
To do that, I made a function and a trigger :
CREATE FUNCTION reCount()
RETURNS TRIGGER AS $function$
BEGIN
UPDATE salary SET totalsalary = netsalary + reward;
RETURN NEW;
END;
CREATE TRIGGER updateTotalsalary
AFTER INSERT OR UPDATE
ON salary
FOR EACH ROW
EXECUTE PROCEDURE reCount();
Finally, I try to test by a query insert like this :
INSERT INTO salary(salaryid,userid,netsalary,reward,totalsalary)
VALUES (1234,123, 30,2,30);
but it run for a long time and it seem never stop. So when a try to stop it with, I got many rows of :
SQL statement "UPDATE salary SET totalsalary = netsalary + reward"
PL/pgSQL function "reCount()" line 3 at SQL statement
So what is the problem. Hope you guys can give me some suggestion?
Try:
CREATE TRIGGER updateTotalsalary
AFTER INSERT OR UPDATE
ON salary
FOR EACH ROW
WHEN (pg_trigger_depth() = 0)
EXECUTE PROCEDURE reCount();
this might be better than the pg_trigger_depth() = 0 hack:
CREATE TRIGGER updateTotalsalary
AFTER INSERT OR UPDATE OF netsalary, reward
ON salary
FOR EACH ROW
EXECUTE PROCEDURE reCount();
For UPDATE events, it is possible to specify a list of columns using
this syntax:
UPDATE OF column_name1 [, column_name2 ... ]
The trigger will only fire if at least one of the listed columns is
mentioned as a target of the UPDATE command.
though personally i'd probably go for a table without the totalsalary column and a view with it (CREATE TABLE salary_ ..., CREATE VIEW salary AS SELECT ..., (salary + reward) AS totalsalary FROM salary_).
Related
I have a table COMMANDE and a table REGROUPE. I have that function:
CREATE OR REPLACE PROCEDURE multiplicateur(a NUMBER, taxes NUMBER, c OUT NUMBER)
IS
BEGIN
c := a * taxes ;
END multiplicateur;
/
I'm trying to make a trigger using that founction to update a total price with taxes from a command that can contain more than one item. I tried this but it doesn't want to work:
create or replace TRIGGER MAJ_PRIX_COMMANDE
AFTER INSERT OR UPDATE OR DELETE ON REGROUPE
FOR EACH ROW
DECLARE
resultat NUMBER;
BEGIN
UPDATE COMMANDE
SET COMMANDE.prixTotal = multiplicateur((CAST((SELECT SUM(prixRegroupe)FROM REGROUPE WHERE REGROUPE.numCommande = :NEW.numCommande)AS NUMBER)),1.15,resultat)
WHERE COMMANDE.numCommande = :NEW.numCommande;
END;
Can someone help me?
How about this? I sent this from my iPhone; this code hasn't been tested.
create or replace TRIGGER MAJ_PRIX_COMMANDE
AFTER INSERT OR UPDATE OR DELETE ON REGROUPE
FOR EACH ROW
DECLARE
resultat NUMBER;
l_groupe NUMBER; --will store sum based on numCommande
BEGIN
--retrieve sum of prixRegroupe
SELECT SUM(r.prixRegroupe)
INTO l_groupe
FROM regroupe r
WHERE r.numCommande = :NEW.numCommande;
--call procedure and pass the sum of priRegroupe
multiplicateur(l_groupe, 1.15, resultat);
--use precedures out argument to update commande
UPDATE COMMANDE c
SET c.prixTotal = resultat
WHERE c.numCommande = :NEW.numCommande;
END;
This code won't work. It will result in a mutating trigger error. Within a trigger you cannot query or modify the same table that the trigger is based on until after the trigger has completed execution.
ORA-04091: table name is mutating, trigger/function may not see it
Your problem right now is that you're querying the regroupe table while the trigger is trying to insert/update the same table. This cannot be accomplished.
You'll need to find a way to get the sum of the prixRegroup column some other way. It's late if I think of anything I'll respond tomorrow.
In my table Team which contains:
Name
Wins
Draws
Losses
Points
Now i want to do a trigger which sum wins, draws, losses and puts it into points column.
Win * 3, Draw * 1, loss * 0
I did something like that:
create or replace
trigger Summ_points
AFTER insert ON Team
FOR EACH ROW
ENABLE
DECLARE
tmp Team.Points%type;
BEGIN
select sum(Wins*3 + Draws + Losses*0) into tmp from Team;
Update Team
set Points=tmp;
END Summ_points;
but it does not work, because all records are updated :/
Language: PL SQl , Oracle
Inside teh trigger you can access and modify only the triggered record and only using :NEW and :OLD references.
Here's how to update a field on the triggered record of the table:
CREATE OR REPLACE TRIGGER sum_points
BEFORE INSERT OR UPDATE ON team
FOR EACH ROW
BEGIN
:NEW.Points := :NEW.Wins * 3 + :NEW.Draws;
END;
Is this what you want?
create or replace
trigger Summ_points
BEFORE insert ON Team
FOR EACH ROW
ENABLE
BEGIN
SELECT (:new.Wins*3 + :new.Draws + :new.Losses*0) into :new.Points
FROM dual;
END Summ_points;
This adds the points in each row. I'm not sure why you would need to add points from multiple rows.
I am using postgresql and I want to update a column by summing up other column in the table.
EX: table name is A. When col1 or col2 or any column value in table A
is updated then the value of col6 should also be updated as
col6=(col1+col2+col3)
for this i have written a update trigger as below.
CREATE FUNCTION update_total2() RETURNS TRIGGER AS $_$
BEGIN
UPDATE hr_contract SET "x_TOTAL"=(NEW.x_othr_allow+NEW.x_med_allw+NEW."x_LTA"+NEW.wage+NEW.supplementary_allowance) WHERE id = OLD.id;
RETURN OLD;
END $_$ LANGUAGE 'plpgsql';
CREATE TRIGGER hr_contract_after_update
AFTER update ON hr_contract
FOR EACH ROW
EXECUTE PROCEDURE update_total2();
It is giving error as below..
ERROR: stack depth limit exceeded
HINT: Increase the configuration parameter "max_stack_depth" (currently 2048kB), after ensuring the platform's stack depth limit is adequate.
CONTEXT: SQL statement "SELECT 1 FROM ONLY "public"."res_users" x WHERE "id" OPERATOR(pg_catalog.=) $1 FOR SHARE OF x"
SQL statement "UPDATE hr_contract SET "x_TOTAL"=(NEW.x_othr_allow+OLD.x_med_allw+OLD."x_LTA"+OLD.wage+OLD.supplementary_allowance) WHERE id = OLD.id"
PL/pgSQL function update_total_result() line 3 at SQL statement
SQL statement "UPDATE hr_contract SET "x_TOTAL"=(NEW.x_othr_allow+OLD.x_med_allw+OLD."x_LTA"+OLD.wage+OLD.supplementary_allowance) WHERE id = OLD.id"
Any help is really very useful...
Try to check if any thing has changed on that row, and set the value of field x_TOTAL if any:
CREATE FUNCTION update_total2() RETURNS TRIGGER AS $_$
BEGIN
--Check if any of columns has been updated:
if tg_op='UPDATE' and old <> new then
NEW."x_TOTAL"= NEW.x_othr_allow+NEW.x_med_allw+NEW."x_LTA"+NEW.wage+NEW.supplementary_allowance);
end if;
RETURN NEW;
END $_$ LANGUAGE 'plpgsql';
--Associate triger to table on BEFORE update events
CREATE TRIGGER hr_contract_after_update
before update ON hr_contract
FOR EACH ROW
EXECUTE PROCEDURE update_total2();
Trigger documentation
I'm not familiar with postgresql syntax but the problem is that you are doing a recursive update. Your function update_total2 must not use UPDATE to the same table being updated on the trigger.
Please check documentation for details, all you have to do in the trigger itself is something like:
FOR EACH ROW
NEW.x_TOTAL = NEW.x_othr_allow + NEW.x_med_allw + NEW."x_LTA" + NEW.wage + NEW.supplementary_allowance
I am looking to set up a trigger that will do some addition(the code below) on two columns if stage_1 or stage_2 is update.
Also is it possible to run the trigger ever 5 min instead of on every update. Thanks In advance for any help.
update monte_carlo_2013 set total = stage_1 + stage_2
I have had a look around the net at trigger and come up with this, which dose not work but am i going in the right direction
CREATE TRIGGER update_stage_1
ON monte_carlo_2013
AFTER INSERT
AS
BEGIN
update monte_carlo_2013 set total_after_1 = (stage_1 + penalty_after_1) WHERE car_num IN (SELECT car_num FROM INSERTED)
END$$
A trigger is not a cronjob, you can also make something like :
CREATE TRIGGER my_first_trigger BEFORE INSERT employees
FOR EACH ROW
BEGIN
IF NEW.id_employee = 55 THEN
INSERT INTO special_employees VALUES (NEW.id_employee, NEW.name);
END IF;
END $$
You juste have to adapt this phpmyadmin-mysql query.
Note : I said phpmyadmin-mysql query because actually "END $$" is used only with phpmyadmin. Normally, we use a system of delimiter.
I want to write a trigger for a table "TRANSACTION".When a new line is inserted, I want to trigger to update the field "TRANSACTIONID" to the maximum + 1 of all the previous records.
I on't know much about SQL. Can someone help me?
many thanks
This is a really bad idea for a multi-user environment, as it will serialise inserts into the table. The usual approach is to use an Oracle sequence:
create sequence transaction_seq;
create trigger transaction_bir before insert on transaction
for each row
begin
:new.id := transaction_seq.nextval;
end;
To write a trigger based solution that actually got the max current value plus 1, you would need to write a complex 3-trigger solution to avoid the "mutating table" issue. Or you could create a simpler solution using another table to hold the current maximum value like this:
create table transaction_max (current_max_id number);
insert into transaction_max values (0);
create trigger transaction_bir before insert on transaction
for each row
declare
l_current_max_id number;
begin
update transaction_max set current_max_id = current_max_id + 1
returning current_max_id into l_current_max_id;
:new.id := l_current_max_id;
end;
This will avoid the mutating table issue and will serialize (slow down) inserts, so I don't see any advantage of this over using a sequence.
CREATE TRIGGER trigger1 on TransactionTable
INSTEAD OF INSERT
AS
BEGIN
DECLARE #MaxTranId INT
SELECT
#MaxTranId = MAX(TransactionId)
FROM
TransactionTable
INSERT INTO TransactionTable
SELECT
#MaxTranId + 1 ,
RestOfYourInsertedColumnsHere ,
FROM
inserted
END
GO