Trigger - Error #1442 Can't update [MYSQL] [duplicate] - mysql

MySQL doesn't currently support updating rows in the same table the trigger is assigned to since the call could become recursive. Does anyone have suggestions on a good workaround/alternative? Right now my plan is to call a stored procedure that performs the logic I really wanted in a trigger, but I'd love to hear how others have gotten around this limitation.
Edit: A little more background as requested. I have a table that stores product attribute assignments. When a new parent product record is inserted, I'd like the trigger to perform a corresponding insert in the same table for each child record. This denormalization is necessary for performance. MySQL doesn't support this and throws:
Can't update table 'mytable' in stored function/trigger because it is already used by statement which invoked this stored function/trigger. A long discussion on the issue on the MySQL forums basically lead to: Use a stored proc, which is what I went with for now.
Thanks in advance!

You can actually up the rows in the same table as the trigger. The thread you linked to even has the solution.
For example:
TestTable ( id / lastmodified / random )
create trigger insert_lastmod
before insert on TestTable
for each row
set NEW.lastmodified = NOW();
insert into TestTable ( `random` ) values ( 'Random' );
select * from TestTable;
+----+---------------------+---------------------+
| id | lastmodified | random |
+----+---------------------+---------------------+
| 1 | 2010-12-22 14:15:23 | Random |
+----+---------------------+---------------------+

I suppose you could call the stored proc in your trigger. HOwever, if you want to update some fields in the same records that you are changing (such as an updatedby or lastupdated column) then you can do this in a beofre trigger according to the refernce manual. http://dev.mysql.com/doc/refman/5.0/en/trigger-syntax.html
This is a common operation for triggers and I find it difficult to believe it isn't supported.

If you want to update column that you don't read in trigger function, then as a workaround, you could put that column into separate table.

You can actually do that
The below is an example for same
DELIMITER $$
create trigger test2
before insert on ptrt
for each row
begin
if NEW.DType = "A" then
set NEW.PA = 500;
elseif NEW.DType = "B" then
set NEW.PA = 1000;
else
set NEW.PA = 0;
END IF;
END;$$
DELIMITER;

This worked for me :D
On Before / Update.
BEGIN
SET NEW.DateTimeUpdated = NOW();
END

Related

Can't update table in stored function/trigger because it is already used by statement which invoked this stored function/trigger in my System [duplicate]

MySQL doesn't currently support updating rows in the same table the trigger is assigned to since the call could become recursive. Does anyone have suggestions on a good workaround/alternative? Right now my plan is to call a stored procedure that performs the logic I really wanted in a trigger, but I'd love to hear how others have gotten around this limitation.
Edit: A little more background as requested. I have a table that stores product attribute assignments. When a new parent product record is inserted, I'd like the trigger to perform a corresponding insert in the same table for each child record. This denormalization is necessary for performance. MySQL doesn't support this and throws:
Can't update table 'mytable' in stored function/trigger because it is already used by statement which invoked this stored function/trigger. A long discussion on the issue on the MySQL forums basically lead to: Use a stored proc, which is what I went with for now.
Thanks in advance!
You can actually up the rows in the same table as the trigger. The thread you linked to even has the solution.
For example:
TestTable ( id / lastmodified / random )
create trigger insert_lastmod
before insert on TestTable
for each row
set NEW.lastmodified = NOW();
insert into TestTable ( `random` ) values ( 'Random' );
select * from TestTable;
+----+---------------------+---------------------+
| id | lastmodified | random |
+----+---------------------+---------------------+
| 1 | 2010-12-22 14:15:23 | Random |
+----+---------------------+---------------------+
I suppose you could call the stored proc in your trigger. HOwever, if you want to update some fields in the same records that you are changing (such as an updatedby or lastupdated column) then you can do this in a beofre trigger according to the refernce manual. http://dev.mysql.com/doc/refman/5.0/en/trigger-syntax.html
This is a common operation for triggers and I find it difficult to believe it isn't supported.
If you want to update column that you don't read in trigger function, then as a workaround, you could put that column into separate table.
You can actually do that
The below is an example for same
DELIMITER $$
create trigger test2
before insert on ptrt
for each row
begin
if NEW.DType = "A" then
set NEW.PA = 500;
elseif NEW.DType = "B" then
set NEW.PA = 1000;
else
set NEW.PA = 0;
END IF;
END;$$
DELIMITER;
This worked for me :D
On Before / Update.
BEGIN
SET NEW.DateTimeUpdated = NOW();
END

Unable to create a MySQL/MariaDB Stored Procedure

I have a XML file which contains 200k records. I have to insert or update the records in the database. My database structure is as followed:
+----+------+-------+-----+-----+------------+
| Id | name | stock | sku | ean | updated_by |
+----+------+-------+-----+-----+------------+
For inserting the records i'm using Doctrine. But it takes to long before all records are inserted or updated. Therefore I want to create a stored procedure.
I tried the following stored procedure but it's not working.
delimiter $$
create trigger insert
before insert on Product
for each row
begin
IF(exists(select 1 From Product WHERE sku = new.sku))
THEN
BEGIN
UPDATE Product SET stock = new.stock WHERE sku = sku;
END;
END IF;
end$$
delimiter
Error:
General error: 1442 Can't update table 'Product' in stored
function/trigger because it is already used by statement which invoked
this stored function/trigger
Update:
You can't use a MySQL trigger in the way you describe. You can't update the table for which the trigger is defined. It would result in an infinite loop.
Even if the trigger code you wrote worked, MySQL does not support "instead of" triggers. That is, it would do the UPDATE but then it would also attempt the INSERT. So it would either create another row with the same sku value, or else if you have a unique constraint on sku, the insert would cause an error and roll back both the INSERT and the UPDATE run from the trigger.
This is why the REPLACE and INSERT...ON DUPLICATE KEY UPDATE statements exist.
I understand you want to use ORM methods for all operations, but this will be a good example of a general rule: ORM's do not support all operations. Inevitably you will encounter a case where you have to write SQL if you want to do something special. Doctrine, like all ORM libraries, supports a way to run literal SQL statements, bypassing the ORM methods.
See Doctrine: ON DUPLICATE KEY UPDATE for example.
You should use insert on duplicate
but your trigger should be li9ke this
your first insert must be the trigger name and the end is missing a ;
delimiter $$
create trigger insert_prodzct
before insert on Product
for each row
begin
IF(exists(select 1 From Product WHERE sku = new.sku))
THEN
BEGIN
UPDATE Product SET stock = new.stock WHERE sku = sku;
END;
END IF;
end$$
delimiter ;

Update foreign key of different row of the same table on UPDATE

I'm using MySql, for my Database and I have a table "Person". Amongst other thing, it contains a relation to itself "Person_MarriedTo" stored as a foreigh_key;
This relation can be null since it's not everybody that's married. What I want to do is that this field can be updated automatically.
if I add A married to B, then B married to A
if B deivorce from A, then A is also divorced from B
I thought triggers would be the way to go, but I can't get my code to work the way I want it to. Any insights would be much appreciated.
Here is my code for the trigger:
USE `mydb`;
DELIMITER $$
CREATE TRIGGER `Person_BUPD` BEFORE UPDATE ON Person FOR EACH ROW
BEGIN
IF OLD.Person_MariedTo != NULL THEN
UPDATE Person SET Person_MariedTo = NULL WHERE UID_Person = OLD.Person_MariedTo;
END IF;
UPDATE Person SET Person_MariedTo = OLD.UID_Person WHERE UID_Person = NEW.Person_MariedTo;
END$$
What you are trying to do is not possible using a trigger.
Within a stored function or trigger, it is not permitted to modify a table that is already being used (for reading or writing) by the statement that invoked the function or trigger. You need to do this some other way.
Source
See here:
MySQL - Trigger for updating same table after insert

Mysql trigger issue (i think it's firing)

I have an issue with a trigger on a mysql database. I have a table such as follows:
id int not null auto_increment (PK)
parent_id int not null,
rank int not null
What I'm trying to do is use a trigger to update the rank to the next highest +10 when they have the same parent_id, but this doesn't seem to be working.
DELIMITER $$
DROP TRIGGER IF EXISTS after_insert $$
create trigger after_insert
after insert on mytable
FOR EACH row
BEGIN
IF EXISTS (SELECT rank FROM mytable WHERE parent_id = new.parent_id AND id != new.id ORDER BY rank DESC LIMIT 1) THEN
UPDATE mytable SET rank = 10
WHERE id = new.id;
ELSE
UPDATE mytable SET rank = 20
WHERE id = new.id;
END IF;
END
$$
I've tried setting the new rank to a variable and calling the update statement using that, and again it didn't work. I even created another table to log what values were being selected and that worked perfectly so I can't quite understand what's going on. Is it a case of, although the trigger is "AFTER INSERT" the insert hasn't actually happened so it can't update the row it's just inserted? Another reason I ask this is, I've even tried updating the rank to different values e.g 1 and 2 depending on which statement it goes to, but it always ends up being 0.
I think you're on the right track with this thought:
Is it a case of, although the trigger is "AFTER INSERT" the insert hasn't actually happened so it can't update the row it's just inserted?
From the FAQ:
B.5.9: Can triggers access tables?
A trigger can access both old and new data in its own table. A trigger can also affect other tables, but it is not permitted to modify a table that is already being used (for reading or writing) by the statement that invoked the function or trigger.
The documentation isn't clear that what you're doing won't work. OTOH, the documentation isn't clear that what you're trying to do will work either.
I think you'd be better off using a BEFORE INSERT trigger and setting NEW.rank in there. Then, the new row would have the right rank value when it is actually inserted into the table rather than patching it after. Also, you'd be able to simplify your existence check to just this:
EXISTS(SELECT rank FROM mytable WHERE parent_id = new.parent_id)
as NEW.id wouldn't have a useful value and the new row wouldn't be in the table anyway; the ORDER BY and LIMIT are also unnecessary as you're just checking if something exists so I took them out.
A BEFORE INSERT trigger seems to match your intent better anyway and that will give you correct data as soon as it is inserted into your table.
If you want the rank to be set +10 more than highest "brother's" rank, you could use:
DELIMITER $$
DROP TRIGGER IF EXISTS whatever $$
create trigger whatever
BEFORE INSERT ON mytable
FOR EACH row
BEGIN
SET NEW.rank = 10 + COALESCE(
( SELECT max(rank)
FROM mytable
WHERE parent_id = NEW.parent_id
), 0 ) ;
END
$$

MySQL triggers cannot update rows in same table the trigger is assigned to. Suggested workaround?

MySQL doesn't currently support updating rows in the same table the trigger is assigned to since the call could become recursive. Does anyone have suggestions on a good workaround/alternative? Right now my plan is to call a stored procedure that performs the logic I really wanted in a trigger, but I'd love to hear how others have gotten around this limitation.
Edit: A little more background as requested. I have a table that stores product attribute assignments. When a new parent product record is inserted, I'd like the trigger to perform a corresponding insert in the same table for each child record. This denormalization is necessary for performance. MySQL doesn't support this and throws:
Can't update table 'mytable' in stored function/trigger because it is already used by statement which invoked this stored function/trigger. A long discussion on the issue on the MySQL forums basically lead to: Use a stored proc, which is what I went with for now.
Thanks in advance!
You can actually up the rows in the same table as the trigger. The thread you linked to even has the solution.
For example:
TestTable ( id / lastmodified / random )
create trigger insert_lastmod
before insert on TestTable
for each row
set NEW.lastmodified = NOW();
insert into TestTable ( `random` ) values ( 'Random' );
select * from TestTable;
+----+---------------------+---------------------+
| id | lastmodified | random |
+----+---------------------+---------------------+
| 1 | 2010-12-22 14:15:23 | Random |
+----+---------------------+---------------------+
I suppose you could call the stored proc in your trigger. HOwever, if you want to update some fields in the same records that you are changing (such as an updatedby or lastupdated column) then you can do this in a beofre trigger according to the refernce manual. http://dev.mysql.com/doc/refman/5.0/en/trigger-syntax.html
This is a common operation for triggers and I find it difficult to believe it isn't supported.
If you want to update column that you don't read in trigger function, then as a workaround, you could put that column into separate table.
You can actually do that
The below is an example for same
DELIMITER $$
create trigger test2
before insert on ptrt
for each row
begin
if NEW.DType = "A" then
set NEW.PA = 500;
elseif NEW.DType = "B" then
set NEW.PA = 1000;
else
set NEW.PA = 0;
END IF;
END;$$
DELIMITER;
This worked for me :D
On Before / Update.
BEGIN
SET NEW.DateTimeUpdated = NOW();
END