What is wrong with my Oracle Trigger? - sql

CREATE OR REPLACE TRIGGER Net_winnings_trigger
AFTER UPDATE OF total_winnings ON Players
FOR EACH ROW
DECLARE
OldTuple OLD
NewTuple NEW
BEGIN
IF(OldTuple.total_winnings > NewTuple.total_winnings)
THEN
UPDATE Players
SET total_winnings = OldTuple.total_winnings
WHERE player_no = NewTuple.player_no;
END IF;
END;
/
I am trying to get a trigger that will only allow the 'total_winnings' field to be updated to a value greater than the current value.
If an update to a smaller value occurs, the trigger should just leave the set the value to the old value (as if the update never occured)

Since you want to override the value that is specified in the UPDATE statement, you'd need to use a BEFORE UPDATE trigger. Something like this
CREATE OR REPLACE TRIGGER Net_winnings_trigger
BEFORE UPDATE OF total_winnings ON Players
FOR EACH ROW
BEGIN
IF(:old.total_winnings > :new.total_winnings)
THEN
:new.total_winnings := :old.total_winnings;
END IF;
END;
But overriding the value specified in an UPDATE statement is a dangerous game. If this is something that shouldn't happen, you really ought to raise an error so that the application can be made aware that there was a problem. Otherwise, you're creating all sorts of potential for the application to make incorrect decisions down the line.

Something like this should work.. although it will be hiding the fact that an update is not taking place if you try to update to a smaller value. To the user, everything will look like it worked but the data will remain unchanged.
CREATE OR REPLACE TRIGGER Net_winnings_trigger
BEFORE UPDATE OF total_winnings
ON Players
FOR EACH ROW
DECLARE
BEGIN
:new.total_winnings := greatest(:old.total_winnings,:new.total_winnings);
END;

Related

This Oracle trigger has problems

create or replace NONEDITIONABLE TRIGGER SumUpdate AFTER INSERT ON stavkaotpremnice FOR EACH ROW
declare pragma autonomous_transaction;
begin
UPDATE otpremnica a
set a.ukupno=
(SELECT SUM(ukupno)
FROM stavkaotpremnice
WHERE brojotpremnice =: new.brojotpremnice)
WHERE a.brojotpremnice = :new.brojotpremnice;
commit;
end;
This trigger is to sum values of a column called "ukupno" in table stavakaotpremnice then store it in another table otpremnica in a column also called "ukupno".
The trigger check if the id(brojotpremnice) is the same and make the sum.
Brojotpremnice is a foreign key from table otpremnica.
Does anyone know why it is totally ignoring the first entry?
If i put rows in stavkaotpremnica i just count the first entry.
This type of problem can be solved via incremental addition as follows:
UPDATE otpremnica a
set a.ukupno = a.ukupno + :new.ukupno
WHERE a.brojotpremnice = :new.brojotpremnice;
Also, please read about pragma autonomous_transaction. Why it is used? Intentional? If you have no idea, read it. (It separates the transaction)

Oracle trigger error ORA-04091

I get an error (ORA-04091: table DBPROJEKT_AKTIENDEPOT.AKTIE is mutating, trigger/function may not see it) when executing my trigger:
CREATE OR REPLACE TRIGGER Aktien_Bilanz_Berechnung
AFTER
INSERT OR UPDATE OF TAGESKURS
OR INSERT OR UPDATE OF WERT_BEIM_EINKAUF
ON AKTIE
FOR EACH ROW
DECLARE
bfr number;
Begin
bfr := :new.TAGESKURS - :new.WERT_BEIM_EINKAUF;
UPDATE AKTIE
SET BILANZ = TAGESKURS - WERT_BEIM_EINKAUF;
IF bfr < -50
THEN
DBMS_OUTPUT.PUT_LINE('ACHTUNG: The value (Nr: '||:new.AKTIEN_NR||') is very low!');
END IF;
END;
I want to check the value "BILANZ" after calculating it, wether it is under -50.
Do you have any idea why this error is thrown?
Thanks for any help!
There are several issues here:
Oracle does not allow you to perform a SELECT/INSERT/UPDATE/DELETE against a table within a row trigger defined on that table or any code called from such a trigger, which is why an error occurred at run time. There are ways to work around this - for example, you can read my answers to this question and this question - but in general you will have to avoid accessing the table on which a row trigger is defined from within the trigger.
The calculation which is being performed in this trigger is what is referred to as business logic and should not be performed in a trigger. Putting logic such as this in a trigger, no matter how convenient it may seem to be, will end up being very confusing to anyone who has to maintain this code because the value of BILANZ is changed where someone who is reading the application code's INSERT or UPDATE statement can't see it. This calculation should be performed in the INSERT or UPDATE statement, not in a trigger. It considered good practice to define a procedure to perform INSERT/UPDATE/DELETE operations on a table so that all such calculations can be captured in one place, instead of being spread out throughout your code base.
Within a BEFORE ROW trigger you can modify the values of the fields in the :NEW row variable to change values before they're written to the database. There are times that this is acceptable, such as when setting columns which track when and by whom a row was last changed, but in general it's considered a bad idea.
Best of luck.
You are modifying the table with the trigger. Use a before update trigger:
CREATE OR REPLACE TRIGGER Aktien_Bilanz_Berechnung
BEFORE INSERT OR UPDATE OF TAGESKURS OR INSERT OR UPDATE OF WERT_BEIM_EINKAUF
ON AKTIE
FOR EACH ROW
DECLARE
v_bfr number;
BEGIN
v_bfr := :new.TAGESKURS - :new.WERT_BEIM_EINKAUF;
:new.BILANZ := v_bfr;
IF v_bfr < -50 THEN
Raise_Application_Error(-20456,'ACHTUNG: The value (Nr: '|| :new.AKTIEN_NR || ') is very low!');
END IF;
END;

Updating value via trigger AFTER UPDATE Oracle 11g

I'm developing a small library database and I don't want to allow someone to update someone's ID. But I need to use AFTER UPDATE and FOR EACH STATEMENT (which I'm told is Oracle's default). So, basically, if someone updates the customer info and alter his/her ID or mistypes it, the trigger will automatically update it again to the old value. The problem is that Oracle won't let me use :NEW and :OLD when using FOR EACH STATEMENT. Are there any workarounds to this issue?
CREATE OR REPLACE TRIGGER alter_id_trigger
AFTER UPDATE ON CUSTOMER
BEGIN
UPDATE CUSTOMER SET ID = :OLD.ID
WHERE ID = :NEW.ID;
END;
Thank you!
Use the below code for trigger.
Changes done:
Using BEFORE UPDATE instead of AFTER UPDATE.
Setting the value of ID to what it was previously. (The ID Field would never be modified)
CREATE OR REPLACE TRIGGER ALTER_ID_TRIGGER
BEFORE UPDATE ON CUSTOMER
BEGIN
SET :NEW.ID = :OLD.ID
END;
Note: With BEFORE UPDATE:
You can not create a BEFORE trigger on a view.
You can update the :NEW values.
You can not update the :OLD values.
I think you want a before update trigger:
CREATE OR REPLACE TRIGGER alter_id_trigger
BEFORE UPDATE ON CUSTOMER
BEGIN
SET :NEW.ID = :OLD.ID
END;
You could test to see if the value is being changed, but that seems unnecessary.

mutating table when writing a trigger

I have been bogged in this problem for quite a long time....Can anyone help me out?
Here is the thing I want to implement:
I have a table A, A has attributes: id, count, total. Here I am required to implement such a trigger: IF the count in table A is updated, the trigger will set the total to 1.
My initial code is like this:
CREATE OR REPLACE TRIGGER tri_A AFTER UPDATE OF count ON A
FOR EACH ROW
BEGIN
UPDATE A SET total = 1 WHERE id = :new.id;
END;
/
The problem with this is the mutating table. When the table is updated, the table will be locked. I searched for the answers, I tried pragma autonomous_transaction, but I got an invalid trigger specification error. And there are other comments saying that we should try to use a combination of triggers to do this....I can't figure out how to do this
Assuming id is the primary key, you don't want to UPDATE the table. You just want to set :new.total. You'll also need to do this in a BEFORE UPDATE trigger not an AFTER UPDATE trigger.
CREATE OR REPLACE TRIGGER tri_A
BEFORE UPDATE OF count ON A
FOR EACH ROW
BEGIN
:new.total := 1;
END;

how to write Instead of update? - Trigger

I have table A and there is a column name COL_A.
I want that if someone change the value, lets say from 1 to 'X' (not costant) that the trigger will change it back from 'X' to 1.
SQLite does not support changing the new column values.
The only way to change a column in a trigger would be to run an UPDATE command,
but that would run the trigger again.
What you can do is to prevent changing the column in the first place:
CREATE TRIGGER IF NOT EXISTS prevent_col_a_change
BEFORE UPDATE OF col_a ON a
BEGIN
SELECT RAISE(ABORT, 'COL_A must not be changed');
END;
UPDATE trigger is a good solution for your case. Just set old value to the new value, that will lead to behaviour you want.
For example:
CREATE OR REPLACE TRIGGER orders_before_update
BEFORE UPDATE
ON orders
FOR EACH ROW
BEGIN
:new.CreatedAt:= :old.CreatedAt;
END;