Postgresql easy update stack limit reached error - sql

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.

Related

Oracle SQL mutating table trigger before update

I want to create an update trigger for a table. The trigger was created, but when I update the column finish, it say mutating table.
This is my code
CREATE OR REPLACE TRIGGER SET_COST BEFORE UPDATE OF finish ON PAY
FOR EACH ROW
BEGIN
UPDATE PAY
SET PAY.COST = (finish-start) * 20000
WHERE PAY.ID=:new.ID;
END;
This trigger gives me 'Mutating Table' error and so far I have been unable to fix it. Any Suggestion ? Thanks
First of all, you shouldn't be doing that at all. There's no use in storing values that are easily calculated whenever you need them.
As of your question: no UPDATE:
begin
:new.cost := (:new.finish - :new.start) * 20000;
end;

Cant get this trigger to work [SQL Oracle]

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;

trigger to update particular column in table A after update on table A

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

Writing an SQL trigger to find if number appears in column more than X times?

I want to write a Postgres SQL trigger that will basically find if a number appears in a column 5 or more times. If it appears a 5th time, I want to throw an exception. Here is how the table looks:
create table tab(
first integer not null constraint pk_part_id primary key,
second integer constraint fk_super_part_id references bom,
price integer);
insert into tab values(1,NULL,100), (2,1,50), (3,1,30), (4,2,20), (5,2,10), (6,3,20);
Above are the original inserts into the table. My trigger will occur upon inserting more values into the table.
Basically if a number appears in the 'second' column more than 4 times after inserting into the table, I want to raise an exception. Here is my attempt at writing the trigger:
create function check() return trigger as '
begin
if(select first, second, price
from tab
where second in (
select second from tab
group by second
having count(second) > 4)
) then
raise exception ''Error, there are more than 5 parts.'';
end if;
return null;
end
'language plpgsql;
create trigger check
after insert or update on tab
for each row execute procedure check();
Could anyone help me out? If so that would be great! Thanks!
CREATE FUNCTION trg_upbef()
RETURN trigger as
$func$
BEGIN
IF (SELECT count(*)
FROM tab
WHERE second = NEW.second ) > 3 THEN
RAISE EXCEPTION 'Error: there are more than 5 parts.';
END IF;
RETURN NEW; -- must be NEW for BEFORE trigger
END
$func$ LANGUAGE plpgsql;
CREATE TRIGGER upbef
BEFORE INSERT OR UPDATE ON tab
FOR EACH ROW EXECUTE procedure trg_upbef();
Major points
Keyword is RETURNS, not RETURN.
Use the special variable NEW to refer to the newly inserted / updated row.
Use a BEFORE trigger. Better skip early in case of an exception.
Don't count everything for your test, just what you need. Much faster.
Use dollar-quoting. Makes your live easier.
Concurrency:
If you want to be absolutely sure, you'll have to take an exclusive lock on the table before counting. Else, concurrent inserts / updates might outfox each other under heavy concurrent load. While this is rather unlikely, it's possible.

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;