Unable to create a MySQL/MariaDB Stored Procedure - mysql

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 ;

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

stored procedure returning `ASCII \0` error but can't find what that is referring to

I am writing my first stored procedure as a trigger. I am doing this in a dev migration as we have two systems which don't speak to each other in dev, so I need to mock the data which would normally come from the other system.
My procedure is added as part of our dev migration script.
DELIMITER |;
CREATE TRIGGER `activity_insert` AFTER INSERT ON `activity`
FOR EACH ROW
BEGIN
UPDATE `activity` AS `a` JOIN `handle` AS `h` on `a.handle_id` = `h.handle_id` SET `path` = CONCAT(`h.handle`,'/',`a.activity_handle`) WHERE `a.path` IS NULL;
END;
|
DELIMITER;
I would expect the logic to be:
DELIMITER $$
CREATE TRIGGER activity_insert BEFORE INSERT ON activity
FOR EACH ROW
BEGIN
IF new.path IS NULL THEN
SET new.path = (SELECT CONCAT(h.handle, '/', new.activity_handle)
FROM handle h
WHERE new.handle_id = h.handle_id
);
END IF;
END;$$
DELIMITER;
There are numerous problem with your code:
You don't update the table being modified using update.
You want a "before" triggers, not an "after trigger".
Don't use | for the the delimited. It is a valid MySQL operator.
You have over-used the backtick, including putting the table alias in with the column alias.
This assumes that handle.handle_id is unique. This seems like a reasonable assumption based on the names, but you can add limit 1 to guarantee no more than one row is returned.

How to solve Error in query (1442) MySql

I am trying to insert some records to a table and update its auto incriment id in another table;
I have a trigger
delimiter #
create trigger test AFTER INSERT ON samples_track for each row begin
update sample_details set sampletrack_id = new.sampletrack_id where sample_details.sample_id = new.sample_id; end#
delimiter ;
And I am running a query
INSERT INTO samples_track(sample_name,customer_id,contact_name,added_by,added_date,status,sample_id)
SELECT sample_name,
customer_id,
clinician_id,
999,
'2016-01-23',
1,
sample_id
FROM sample_details
WHERE sampletrack_id IS NULL;
The result is as below
Error in query (1442): Can't update table 'sample_details' in stored
function/trigger because it is already used by statement which invoked
this stored function/trigger.
Well, the reason of this error is that when you insert a record mysql locks the table. you can't insert/update/delete rows of the same table where you insert.. because then the trigger would called again and again.. ending up in a recursion.
To solve your problem, have a look at this thread. Also, in this forum they suggest to use a before insert trigger... Worth a try.

Error Code: 1442. Can't update table 'students' in stored function/trigger

I have the following trigger:
CREATE DEFINER=root#localhost TRIGGER after_insert_student after INSERT ON
students FOR EACH ROW BEGIN
SET #NEWID := NEW.ID ;
if #NEWID IS NOT NULL THEN
INSERT INTO students SET ID = #NEWID;
else
INSERT INTO students SET ID = 001;
END IF
END
ERROR:
Error Code: 1442. Can't update table 'students' in stored
function/trigger because it is already used by statement which
invoked this stored function/trigger.
You cannot change a table while the INSERT trigger is firing. The INSERT might do some locking which could result in a deadlock. Also, updating the table from a trigger would then cause the same trigger to fire again in an infinite recursive loop. Both of these reasons are why MySQL prevents you from doing this.
To do this, please reference this link
You probably want a BEFORE INSERT trigger. Then instead of updating the table, just assign the desired value to NEW.ID.
The problem is that you can't write statement like
INSERT INTO students SET ID = #NEWID;
because it requires to know which columns you want to insert, or if not columns specified then you insert into all columns values etc.
INSERT INTO students values (#NEWID);
should work or if you want to stick to your SET ID then try to write something like
UPDATE students SET ID = #NEWID;
Hope this guides you to solution to your problem.
Solution: make it a BEFORE UPDATE ON trigger, and use NEW operator, it'll do the job - as all you want is if new ID is NULL set it to 001:
CREATE DEFINER=root#localhost TRIGGER after_insert_student
BEFORE INSERT ON students
FOR EACH ROW BEGIN
IF NEW.ID IS NULL THEN
SET ID = 001;
END IF;
END;
Cause: You cannot update a table (students) where the trigger is invoked:
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.
Doing so will generate Error 1442:
Error Code: 1442
Can't update table 'chatroompost' in stored function/trigger because it is already used by statement which invoked this stored function/trigger.

Trigger - Error #1442 Can't update [MYSQL] [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