Cant get this trigger to work [SQL Oracle] - sql

CREATE TRIGGER Alerta_Trig
BEFORE INSERT OR UPDATE OF Valor ON Medicao
FOR EACH ROW
WHEN (NEW.VALOR > 40)
BEGIN
UPDATE SENSOR
SET ALERTA = 'Alerta laranja'
WHERE SENSOR_ID=(SELECT SENSOR_SENSOR_ID FROM MEDICAO);
END;
I have this table of Sensors that are supposed to receive a String with an alert if 1 value > 40 enters the Medicao table. Any thoughs?

As you haven't said quite what is wrong I'm speculating a bit, but I can see two immediate potential problems.
You shouldn't query the same table again, generally, as you'll risk get a mutating table error. You also have no condition in the subquery so you'd be likely to get multiple rows back, and a subquery-returns-more-than-one-row error.
Presumably you're doing that subquery to try to get the ID value from the affected row, so use the :NEW pseudo-row for that:
CREATE TRIGGER Alerta_Trig
BEFORE INSERT OR UPDATE OF Valor ON Medicao
FOR EACH ROW
WHEN (NEW.VALOR > 40)
BEGIN
UPDATE SENSOR
SET ALERTA = 'Alerta laranja'
WHERE SENSOR_ID = :NEW.SENSOR_SENSOR_ID;
END;

Related

ORA-04091 Error on "after update" trigger, how to get around?

I have a trigger set to fire after an update of a specific column. I want to update the value of a specific column after a specific value from another column changes to another specific value.
I'm getting the errors:
ORA-04091: table tableName is mutating, trigger/function may not see it
ORA-06512: at "triggerName", line 14
ORA-04088: error during execution of trigger 'triggerName'
I've rewritten this as a before update and after update, as well as tried storing the logic in a function, and using "pragma autonomous_transaction", but the error still gets thrown.
BEFORE update of columnName1 ON tableName
FOR EACH ROW
BEGIN
if :new.columnName1 = 3 AND :old.columnName1 = 1 then
update tablename
set columnName2= MOD(sequenceName.NextVal, 5) + 1
where tableName.columnName2 = :old.columnName2;
end if;
END;
/
I don't understand why the entire table is labelled as "mutating" when I am not updating the column affected by the update the trigger is responding to. Surely, you should be able to update the value of a column in a table if another value in the table changes, or am I crazy here?
Note: Only one entry would be affected at a time. In my application logic, I update the status of some person in the database. I want the database to do some logic only on a specific status change, and I want to avoid using API calls for the logic here, as you can see, it is simply one line of logic in PLSQL.
Thanks
Perhaps you don't really want to update the table but just change a value in the specific row being updated.
If so, eschew the update and just set the value:
BEFORE update of columnName1 ON tableName
FOR EACH ROW
BEGIN
if :new.columnName1 = 3 AND :old.columnName1 = 1 then
:new.columnName2 := MOD(sequenceName.NextVal, 5) + 1 ;
end if;
END;

Postgresql easy update stack limit reached error

I have a super simple table
id, entries, max_capacity, factor
So we have ex 500 max capacity and 250 entries and it should be 50 (50% full) easy right?
Problem is when I update the entries I want the factor to auto update as well, so I have done the function:
create function myUp() returns trigger as $$
begin
update myTable
set factor=round(100*(entries/max_capacity),0);
end;
$$ language plpgsql;
and the trigger
create trigger myUp
after insert or update on myTable
for each row
execute procedure myUp();
and I get a new trigger function and running an update example
update myTable
set entries=500
where id=1;
Where I update the entries on one of the rows and I get the ERROR stack depth limit exceeded CONTEXT update myTable....
Why do I get this? Do I have to set the entries for all of the rows for it to work? I have no clue why it is not working. I want the after because I cant calculate the value before I inserted the new entries values.

Mutating table exception when selecting max(date column of TABLE_X) in an after update trigger for TABLE_X

I have a trigger somewhat like this (Sorry can't display actual sql because of company rules and this is from a different machine):
create or replace trigger TR_TABLE_X_AU
after update
on TABLE_X
for each row
declare
cursor cursor_select_fk is
select FK_FOR_ANOTHER_TABLE
from TABLE_Y Y, TABLE_Z Z
where :NEW.JOINING_COL = Y.JOINING_COL
and Y.JOINING_COL = Z.JOINING_COL
and :NEW.FILTER_CONDITION_1 = Y.FILTER_CONDITION_1
and :NEW.FILTER_CONDITION_2 = Y.FILTER_CONDITION_2
and :NEW.SOME_DATE_COL = (select max(SOME_DATE_COL)
from TABLE_X
where FILTER_CONDITION_1 = :NEW.FILTER_CONDITION_1
and FILTER_CONDITION_2 = :NEW.FILTER_CONDITION_2)
begin
for rec in cursor_select_fk loop
PCK_SOME_PACKAGE.SOME_PROC(rec.FK_FOR_ANOTHER_TABLE);
end loop;
end TR_TABLE_X_AU;
We resulted to triggers since it is an enhancement. The nested query selecting the max date seems to be the cause of the problem. Changing it to sysdate results to no exceptions. Any idea on how I can get the max date during the execution of the trigger for TABLE_X? Thanks!
EDIT:
Also, it seems similar functions such as count,sum,etc... produces the same error. Anyone knows a workaround to this?
A mutating table is a table that is being modified by an UPDATE,
DELETE, or INSERT statement, or a table that might be updated by the
effects of a DELETE CASCADE constraint.
The session that issued the triggering statement cannot query or
modify a mutating table. This restriction prevents a trigger from
seeing an inconsistent set of data.
Trigger Restrictions on Mutating Tables
Which means, you cannot issue max(some_date_col) on your TABLE_X in a row-level trigger.
Compound trigger could be a possible workaround.

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;

oracle trigger after inserting or updating a sales item

I have this table that represents a weak entity and is a typical table for introducing items ordered:
insert into ITEM_FORNECIMENTO values (a_orderId,a_prodId,a_prodQtd, a_buyPrice);
I want my trigger to update the last column (the total price of products WITHOUT iva) to do this : totalPrice= totalPrice*(1+(iva/100), each time I insert or update an entry on that table.
so, I came up with this, but I'm totally wrong when it comes to work with new and old values.
create or replace
trigger t_replaceTotal
after insert or update of id_prod,qtd_if,prec_total_if on item_fornecimento
for each row
declare
iva produto.iva_prod%type;
idProd produto.id_prod%type;
r_old item_fornecimento.prec_total_if%type:=null;
r_new item_fornecimento.prec_total_if%type:=null;
begin
select iva_prod,id_prod into iva,idprod from produto p where p.id_prod = id_prod;
r_old:= :old.prec_total_if;
r_new:= :new.prec_total_if;
update item_fornecimento item set prec_total_if = r_old * (1+(iva/100)) where item.id_prod = idprod;
end;
Could someone please help rewriting this code? I'm getting the error: ORA-01422: exact fetch returns more than requested number of rows
ORA-06512: at "FUSION.T_REPLACETOTAL", line 8
ORA-04088: error during execution of trigger 'FUSION.T_REPLACETOTAL'
The problem is that you are trying to fetch every row from the table because you are matching a column (id_prod) to itself. I suspect you want to use :new.id_prod or :old.id_prod.
select .... from produto p where p.id_prod = id_prod;
Next, make this a BEFORE INSERT/UPDATE trigger and replace the UPDATE statement with
:new.prec_total_if := r_old * (1+(iva/100));
Otherwise you'll get a mess of mutating table errors.
That error is telling you that a query that saves its result into a variable is returning more than one result. As such it doesn't know what you want to save in the variable.
Try running the following:
select iva_prod,id_prod from produto p where p.id_prod = id_prod;
and I bet it will give you more than one result, which it can't save into iva,idprod.