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.
Related
I am making a price list that automatically updates prices based on certain variables set.
When changing the cost of the items (i know my column names suck) or the time spent, the date modified field should change for only the record that had changed, instead the date modified field changes for every record on the table. There are several triggers that fire in order to update the prices in the table.
I don't know how to split this file so that its easier to access the database but attached is a link to the database (libreoffice base 6.2.3.2 using firebird 3.0 embedded)
https://drive.google.com/open?id=1dFedDfd2JtmvMk8ChVofDpSDN8hq0p_S
// Date modified trigger
CREATE TRIGGER TRGDATEMODIFIED for "tblPart"
before insert or update Position 100
AS
BEGIN
new."Date Modified" = current_timestamp;
END
//Set Total Price Trigger (last trigger to fire to set price all other triggers set the values for )
CREATE TRIGGER TRGSETTOTALPRICE for "tblPart"
After insert or update position 99
AS
BEGIN
IF (old."Price" is distinct from new."Price" or old."Labor Price" is distinct from new."Labor Price" )
Then
Update "tblPart"
Set "Total Price" = (CEIL(("Price"+"Labor Price")/10)*10)+9;
END
// trigger to set price that trigger TRGSETTOTALPRICE uses
CREATE TRIGGER TRGSETPARTPRICE for "tblPart"
After insert or update Position 98
AS
BEGIN
IF (old."Cost" is distinct from new."Cost")
Then
Update "tblPart"
Set "Price" = "tblPart"."Cost" / ( 1 -(Select "tblVariables"."Margin"from "tblVariables")) ;
END
// Trigger that uses second table for values that wont accept the "new" psuedotable
CREATE TRIGGER TRGSETPARTPRICE2 for "tblVariables"
After insert or update Position 98
AS
BEGIN
IF (old."Margin" is distinct from new."Margin")
Then
Update "tblPart"
Set "Price" = "tblPart"."Cost" / ( 1 -(Select "tblVariables"."Margin"from "tblVariables")) ;
END
// and my attempt to edit to work correctly
CREATE TRIGGER TRGSETPARTPRICE2 for "tblVariables"
Before insert or update Position 98
AS
BEGIN
IF (old."Margin" is distinct from new."Margin")
Then
new."Price" = (select "tblPart"."Cost" from "tblPart") / ( 1 -(Select "tblVariables"."Margin"from "tblVariables")) ;
END
//code that should update all values when margin is changed
CREATE TRIGGER TRGSETLABORPRICE for "tblVariables"
after insert or update position 98
AS
BEGIN
IF (old."Time Segment" is distinct from new."Time Segment" or old."Margin" is distinct from new."Margin" )
Then
update "tblPart"
set "Labor Price" =
Ceil((((select "Overhead with Margin" from "tblVariables") / (60/(select "Time Segment"from "tblVariables")))* Ceil(("Time to Complete"."tblPart")/( select "Time Segment"from "tblVariables"))));
END
//edit: Fixed code all runs , but the last code snippet feels like its implemented wrong but works nevertheless
You are doing an unconditional update on all the rows in the tblpart table in the TRGSETTOTALPRICE and TRGSETPARTPRICE triggers. You shouldn't modify the targeted table in a trigger like this, instead you should use a before trigger and perform the modification on the new context variable. That context variable is modifiable in a before trigger exactly for this purpose.
That is, you should do:
CREATE TRIGGER TRGSETTOTALPRICE for "tblPart"
before insert or update position 99
AS
BEGIN
IF (old."Price" is distinct from new."Price" or old."Labor Price" is distinct from new."Labor Price" )
Then
new."Total Price" = CEIL((new."Price" + new."Labor Price") / 10) * 10 + 9;
END
and
CREATE TRIGGER TRGSETPARTPRICE for "tblPart"
before insert or update Position 98
AS
BEGIN
IF (old."Cost" is distinct from new."Cost")
Then
new."Price" = new."Cost" / ( 1 - (Select "tblVariables"."Margin" from "tblVariables"));
END
You need to do a join on the "updated" or "inserted" table to change only the records affected by the trigger.
See a similar answer here: https://dba.stackexchange.com/questions/118648/how-to-reference-only-affected-rows-in-after-update-trigger
I'm new to SQL and I'm trying to update a column (ex_counter) of a table (ex_table). This column consists of a counter of the number of times an ID (ex_id) appears on a second table (ex2_id in ex2_table).
An ID can be inserted into the second table at any moment. If that ID is already existing, the counter of its corresponding ID in the first table must be updated (by simply adding 1, I guess).
These are the two tables:
CREATE TABLE ex_table(
ex_id SMALLINT,
ex_counter SMALLINT;)
CREATE TABLE ex2_table(
ex2_id SMALLINT;)
I think it should be done more or less like this. The commented code is the pseudocode that I don't know how to implement:
CREATE TRIGGER ex_trigger AFTER
INSERT ON ex2_table
FOR EACH ROW EXECUTE PROCEDURE ex_func();
CREATE FUNCTION ex_func() RETURNS trigger AS $$ BEGIN
/*
if ex2_id = ex_id
ex_counter = ex_counter + 1
*/
RETURN NULL;
END;
$$ LANGUAGE plpgsql;
Thanks in advance!
Something like this
IF EXISTS (SELECT * FROM ex_table WHERE ex_id = new.ex2_id) THEN
UPDATE ex_table
SET ex_counter = ex_counter + 1
WHERE ex_id = new.ex2_id
ELSE
INSERT INTO ex_table VALUES (new.ex2_id, 1)
END IF;
Note that it is no point really to store a counter since you so easily can retrieve the value by doing a SELECT COUNT()...
I want a trigger that updates the value of a column, but I just want to update a small set of rows that depends of the values of the inserted row.
My trigger is:
CREATE OR REPLACE TRIGGER example
AFTER INSERT ON table1
FOR EACH ROW
BEGIN
UPDATE table1 t
SET column2 = 3
WHERE t.column1 = :new.column1;
END;
/
But as I using FOR EACH ROW I have a problem when I try it, I get the mutating table runtime error.
Other option is not to set the FOR EACH ROW, but if I do this, I dont know the inserted "column1" for comparing (or I dont know how to known it).
What can I do for UPDATING a set of rows that depends of the last inserted row?
I am using Oracle 9.
You should avoid the DML statements on the same table as defined in a trigger. Use before DML to change values of the current table.
create or replace trigger example
before insert on table1
for each row
begin
:new.column2 := 3;
end;
/
You can modify the same table with pragma autonomous_transaction:
create or replace trigger example
after insert on table1 for each row
declare
procedure setValues(key number) is
pragma autonomous_transaction;
begin
update table1 t
set column2 = 3
where t.column1 = key
;
end setValues;
begin
setValues(:new.column1);
end;
/
But I suggest you follow #GordonLinoff answere to your question - it's a bad idea to modify the same table in the trigger body.
See also here
If you need to update multiple rows in table1 when you are updating one row, then you would seem to have a problem with the data model.
This need suggests that you need a separate table with one row per column1. You can then fetch the value in that table using join. The trigger will then be updating another table, so there will be no mutation problem.
`create table A
(
a INTEGER,
b CHAR(10)
);
create table B
(
b CHAR (10),
d INTEGER
);
create trigger trig1
AFTER INSERT ON A
REFERENCING NEW AS newROW
FOR EACH ROW
when(newROW.a<=10)
BEGIN
INSERT into B values(:newROW.b,:newROW.a);
END trig1;
insert into A values(11,'Gananjay');
insert into A values(5,'Hritik');
select * from A;
select * from B;`
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_).
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