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 ;
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 am trying to create a trigger to update last_modified field when the row is updated.
This is what i have tried:
USE `mydb`;
DELIMITER $$
DROP TRIGGER IF EXISTS mydb.products_AUPD$$
USE `mydb`$$
CREATE TRIGGER `products_AUPD` AFTER UPDATE ON products
FOR EACH ROW BEGIN
SET NEW.`last_modified` = NOW();
END;
$$
DELIMITER ;
The problem is MySQL workbench wont let me save it (I'm assuming that there is something wrong with it but i can't find out what)
Turns out the version of MySQL Workbench I was using(6.0xxx) had a bug in it which played havoc with triggers. I updated to 6.2xxx.
That was the first problem.
The second problem was that i was using the NEW keyword in an AFTER trigger which is not allowed:
Within the trigger body, you can refer to columns in the subject table
(the table associated with the trigger) by using the aliases OLD and
NEW. OLD.col_name refers to a column of an existing row before it is
updated or deleted. NEW.col_name refers to the column of a new row to
be inserted or an existing row after it is updated.
So my new trigger looks like this:
CREATE DEFINER = CURRENT_USER TRIGGER `mydb`.`products_BEFORE_UPDATE` BEFORE UPDATE ON `products` FOR EACH ROW
BEGIN
SET NEW.`last_modified` = NOW();
END;
Notice there is no USE or DELIMITER statement? That is because the new version of MySQL Workbench puts this in for you (including the end delimiter $$):
USE `mydb`;
DELIMITER $$
USE `mydb`$$
DROP TRIGGER IF EXISTS `mydb`.`products_BEFORE_INSERT` $$
USE `mydb`$$
CREATE DEFINER = CURRENT_USER TRIGGER `mydb`.`products_BEFORE_INSERT` BEFORE INSERT ON `products` FOR EACH ROW
BEGIN
SET NEW.`last_modified` = NOW();
END;$$
I'm trying to remove a row after inserted in a temp table and I get this error:
INSERT INTO `temp_program_counter` (`id`, `program_id`) values (NULL, '275')
Can't update table 'temp_program_counter' in stored function/trigger because it is already used by statement which invoked this stored function/trigger.
And here is my trigger:
DELIMITER $$
DROP TRIGGER IF EXISTS `testtemp`$$
CREATE
TRIGGER `testtemp` AFTER INSERT ON `temp_program_counter`
FOR EACH ROW BEGIN
UPDATE `program` SET `view_count`=`view_count`+1;
DELETE FROM `temp_program_counter` WHERE id=new.id;
END;
$$
DELIMITER ;
this table is a temp table that get's data with delay and after receiving must update the main table and be deleted from temp.
thanks for helping in advance.
You probably have already resolved this in some way but I'll post the answer anyway:
You cannot refer to the same table that triggered the trigger in a trigger (or a combination of trigger and stored procedure). This could mean an infinite loop, so sql prevents it by giving that error, resulting in always the same error.
Try BEFORE INSERT
Because, you are trying to delete a record which has just been inserted but may be not yet committed in this session. Hence you are getting the error.
If you use BEFORE INSERT, then all other record in the table with id=new.id would be deleted and the new record will be inserted successfully.
DELIMITER $$
DROP TRIGGER IF EXISTS `testtemp`$$
CREATE
TRIGGER `testtemp` BEFORE INSERT ON `temp_program_counter`
FOR EACH ROW BEGIN
UPDATE `program` SET `view_count`=`view_count`+1;
DELETE FROM `temp_program_counter` WHERE id=new.id;
END;
$$
DELIMITER ;
In MySQL I tried to define a trigger like this:
DELIMITER $$
CREATE TRIGGER vipInvite
AFTER INSERT ON meetings
FOR EACH ROW
BEGIN
IF(NOT EXISTS (SELECT * FROM participants
WHERE meetid = NEW.meetid AND pid ='vip'))
THEN
IF(EXISTS(SELECT * FROM meetings WHERE meetid = NEW.meetid AND slot > 16))
THEN
INSERT INTO participants(meetid, pid)
VALUES (NEW.meetid,(SELECT userid
FROM people WHERE people.group = 'tap' GROUP BY invite));
END IF;
END IF;
END $$
DELIMITER ;
Produces this error:
This version of MySQL doesn't yet support 'multiple triggers with the same action time and event for one table.
Is there a way to work around this so I can define multiple triggers?
This error means you already have an AFTER INSERT trigger on meetings table.
If it is the same trigger (meaning vipInvite) that you created earlier and now you want to replace it then you need to drop it first
DROP TRIGGER vipInvite;
DELIMITER $$
CREATE TRIGGER vipInvite
...
END$$
DELIMITER ;
Now if you have some other trigger you have to merge code from both triggers into one, then drop existing trigger, and then create a new one.
To show the list of existing triggers use SHOW TRIGGERS.
SHOW TRIGGERS WHERE `table` = 'meetings';
How to reproduce this error in MySQL:
ERROR 1235 (42000): This version of MySQL doesn't yet support 'multiple
triggers with the same action time and event for one table'
Run the following queries:
DELIMITER //
CREATE TRIGGER mytrigger1 AFTER INSERT ON mytable
FOR EACH ROW
BEGIN
END//
DELIMITER //
CREATE TRIGGER mytrigger2 AFTER INSERT ON mytable
FOR EACH ROW
BEGIN
END//
If you want to hook more than one action onto the same event/table, you will have to cram all of it into one trigger. You could call many stored procedures like this:
DELIMITER //
CREATE TRIGGER mytrigger1 AFTER INSERT ON mytable
FOR EACH ROW
BEGIN
CALL fromulate_the_moobars(NEW.myid);
CALL its_peanut_butter_jelly_time(NEW.myname);
END//
I wrote the trigger below, but when I insert into the table it doesn't capitalize the inserted word, like it is supposed to. (no errors either). Any possible solutions?
(I have an employee and an employee2 table, since I read you cant have the trigger in the table it is trying to update).
DELIMITER $$
DROP TRIGGER IF EXISTS mytrigger$$
CREATE TRIGGER mytrigger before INSERT ON employee FOR EACH ROW
BEGIN
update employee2
SET employee2.FName = CONCAT(UCASE(LEFT(employee2.FName, 1)), LCASE(SUBSTRING(employee2.FName, 2)));
END;
$$
DELIMITER ;
You can have triggers on the table you are trying to update, you just can't run UPDATE queries. Instead, you modify the data before it is inserted:
DELIMITER $$
DROP TRIGGER IF EXISTS mytrigger$$
CREATE TRIGGER mytrigger before INSERT ON employee FOR EACH ROW
BEGIN
SET NEW.FName = CONCAT(UCASE(LEFT(NEW.FName, 1)), LCASE(SUBSTRING(NEW.FName, 2)));
END;
$$
DELIMITER ;
The "NEW" keyword gives you access to the data that is going to be inserted.