delimiter //
create trigger T1 before update on account
for each row
if NEW.balance <= 0 then
update account set balance=OLD.balance;
end if;
//
Query OK, 0 rows affected (0.09 sec)
delimiter ;
update account set balance=-1 where id=101;
ERROR 1442 (HY000): Can't update table 'account' in stored function/trigger because it is already used by statement which invoked this stored function/trigger.
MySQL uses row level triggers, so the trigger is fired for each row that is being changed. Because of that there is no reason to update the target table, just assign the value:
create trigger T1 before update on account
for each row
if NEW.balance <= 0 then
set new.balance = OLD.balance; -- this is the difference
end if;
SQLFiddle example: http://sqlfiddle.com/#!2/34aebb/1
Your update wouldn't have worked anyway because it was missing a where clause which means you would have updated the entire table just because a single row was changed.
Related
I have a table named Client , I want to update the available credit column after updating the balance field.
I created this trigger
DELIMITER $$
CREATE TRIGGER client_update_balance
AFTER UPDATE ON client
FOR EACH ROW
BEGIN
update client
set AvailableCredit = CreditLimit - new.Balance;
END
But when I update a balance value like that
SET SQL_SAFE_UPDATES = 0;
UPDATE client
SET
balance = 1500
WHERE
client.ClientNum = 143;
I get this error:
Error Code: 1442. Can't update table 'client' in stored function/trigger because it is already used by statement which invoked this stored function/trigger.
Checked some StackOverflow answers and tried without Update statement inside
DELIMITER $$
CREATE TRIGGER client_update_balance
AFTER UPDATE ON client
FOR EACH ROW
BEGIN
set New.AvailableCredit = New.CreditLimit - New.Balance;
END;$$
DELIMITER ;
I get another error
Error Code: 1362. Updating of NEW row is not allowed in after trigger
Use a before update trigger and just set the value:
DELIMITER $$
CREATE TRIGGER client_update_balance
BEFORE UPDATE ON client
FOR EACH ROW
BEGIN
set new.AvailableCredit = new.CreditLimit - new.Balance;
END;
The idea is that you want to change values in the same row of the table being updated. You don't need a separate update transaction to do that. You just need to adjust the values.
That said, if AvailableCredit is always defined as this difference, you should use a generated column. That way, you don't have to update the value. It is just correct when you query the table.
I need to update the parent item's updated_at field when any of it's child item's updated_at field is updated.
DELIMITER $$
CREATE TRIGGER after_item_update
AFTER UPDATE
ON item FOR EACH ROW
BEGIN
IF OLD.updated_at <> NEW.updated_at AND OLD.parent_id > 0 THEN
UPDATE item i set updated_at = now() where i.id = OLD.parent_id;
END IF;
END$$
DELIMITER ;
I tried above query but it gives me following error when I try to update any row from the table.
ERROR 1442 (HY000): Can't update table 'item' in stored function/trigger because it is already used by statement which invoked this stored function/trigger.```
I am trying to create as following given:
Create a trigger on the Company table after an update that sets a
company's budget to 0 if it is less than 0.
But I struggle with errors such as being unable to update, set the table. I know it is because of I need to change from 'after update' to 'before update'. But I cannot dismiss the expected code. What could I do?
The mySQL code I have is:
delimiter $$
drop procedure if exists after_company_update $$
create trigger after_company_update after update on Company
for each row begin
update Company set budget = 0 where budget < 0;
end $$
delimiter ;
Error: ER_CANT_UPDATE_USED_TABLE_IN_SF_OR_TRG: Can't update table 'Company' in stored function/trigger because it is already used by statement which invoked this stored function/trigger.
Such a trigger should logically be done before the update rather than afterwards:
delimiter $$
drop trigger if exists before_company_update $$
create trigger before_company_update after update on Company
for each row
begin
if old.budget < 0 then
set new.budget := 0
end if;
end $$
delimiter ;
You can express this as an after update trigger:
create trigger after_company_update after update on Company
for each row
update Company
set budget = 0
where Company.Id = new.Id;
The syntax works, but the trigger doesn't. It returns the error:
Can't update table 'Company' in stored function/trigger because it is already used by statement which invoked this stored function/trigger.
You can see this here.
You can't update the whole table which is already used by the trigger but you can update the column which is been modified.
Assuming your table has Primary Key which is company_id
Like
update Company
set budget = 0
where company_id=new.company_id and budget < 0;
'In an UPDATE trigger, you can use OLD.col_name to refer to the columns of a row before it is updated and NEW.col_name to refer to the columns of the row after it is updated' - https://dev.mysql.com/doc/refman/8.0/en/trigger-syntax.html
A before trigger would work but I'm not sure that it would be appropriate to have a trigger at all - do you really want to do this every time an update occurs to company (or only on specific occasions) , for example would it be appropriate if you changed address(assuming address is in the company table)
delimiter $$
drop trigger if exists after_company_update $$
create trigger after_company_update BEFORE update on Company
for each row begin
set NEW.budget = 0 where OLD.budget < 0;
end $$
DELIMITER ;
I need to update the status column of all the old rows of a table to false before/after inserting a new row into that table.
I have visited these but didn't solve my query.
MySQL - Trigger for updating same table after insert
DELIMITER $$
DROP TRIGGER update_old_status $$
CREATE TRIGGER update_old_status
BEFORE INSERT ON table_name
FOR EACH ROW
BEGIN
DECLARE MYCOUNTER INT;
SELECT COUNT(*) INTO MYCOUNTER FROM table_name;
IF (MYCOUNTER > 0) THEN
UPDATE table_name SET status = false WHERE status = true;
END IF;
END $$
DELIMITER ;
Here what i have as error message:
Caused by: java.sql.SQLException: Can't update table 'table_name' in stored function/trigger because it is already used by statement which invoked this stored function/trigger.
You can't use a trigger to update the same table for which the trigger is running, because there's too high a risk of creating an infinite loop.
For example, an insert trigger updates its table, which runs another trigger on update, that inserts to the same table, which runs the insert trigger...
You can't and don't need to use a trigger for this. Instead, use a transaction and run the UPDATE before your INSERT in your application.
Pseudocode:
START TRANSACTION;
UPDATE table_name SET status = false;
INSERT INTO table_name ...values...
COMMIT;
I want to create a trigger that inserts a timestamp to table log before I update column within a table. For example if I update table hits column number from 1 to 2. I want the time recorded before the column was updated, but this record of the time the update was done must only be when hits.number is updated. How can this be done?
You just need to check if old.number <> new.number then insert.
mysql> delimiter //
mysql> CREATE TRIGGER upd_check BEFORE UPDATE ON hits
-> FOR EACH ROW
-> BEGIN
-> IF NEW.number <> OLD.number THEN
-> INSERT ...
-> END IF;
-> END;//