Ошибка 1442 mysql

I have the following trigger:

CREATE TRIGGER sum
AFTER INSERT
ON news
FOR EACH ROW
UPDATE news SET NEW.sum = (NEW.int_views + NEW.ext_views)/NEW.pageviews

It sums the int_views and ext_views column of a table and divides them by the total pageviews.

Whenever I try to add a new row to news, I get the following error:

ERROR 1442 (HY000) at line 3: Can't update table 'news' in stored function/trigger because it is already used by statement which invoked this stored function/trigger.

The trigger seems pretty simple to me. Is there a reason why the trigger fails to run?

asked Aug 30, 2012 at 19:13

egidra's user avatar

2

The symptom is, that you are running an UPDATE (for all rows) inside a INSERT trigger — both modify the table, which is not allowed.

That said, if I guess the intention of your trigger correctly, you do not want to update all rows, but only the newly inserted row. You can achieve that easily with

CREATE TRIGGER sum
BEFORE INSERT
ON news
FOR EACH ROW
SET NEW.sum = (NEW.int_views + NEW.ext_views)/NEW.pageviews

Mind that this is a BEFORE INSERT trigger, as you want to change the row before it is written to the table.

answered Aug 30, 2012 at 19:22

Eugen Rieck's user avatar

Eugen RieckEugen Rieck

63.9k10 gold badges70 silver badges92 bronze badges

1

If you try to update/insert on the same table that cause trigger to fire do not use the common sql command like

-> UPDATE TABLE_NAME SET COLUMN_NAME = VALUE WHERE CONDITION_LIST;  
-> INSERT INTO TABLE_NAME VALUES("VALUE1","VALUE2");

This will not work. Only use set to assign the value of the column you update.

Example:

CREATE TRIGGER trigger_name BEFORE/AFTER INSERT/UPDATE ON table_name
FOR EACH ROW
SET NEW.COLUMN_NAME = "VALUE";

Richard's user avatar

Richard

6,7725 gold badges45 silver badges60 bronze badges

answered Dec 22, 2014 at 8:54

George Mulokozi's user avatar

1

I was in a similar condition where I had to run two triggers:

  1. UPDATE 3 fields on INSERTing a new ROW
  2. UPDATE 3 fields on UPDATEing a ROW

After lot of efforts, I was finally able to write the TRIGGER in following way:

FOR updating values on INSERT

CREATE TRIGGER `INSERT_DISCOUNT_SERVICES` BEFORE INSERT ON `services`
FOR EACH ROW SET 
NEW.discount_5_rate = (NEW.ndis_rate*0.05),
NEW.discount_10_rate=(NEW.ndis_rate*0.10),
NEW.discount_15_rate=(NEW.ndis_rate*0.15)

Similarly

FOR updating values on UPDATE

CREATE TRIGGER `UPDATE_DISCOUNTS_SERVICES` BEFORE UPDATE ON `services`
FOR EACH ROW SET 
NEW.discount_5_rate = (NEW.ndis_rate*0.05), 
NEW.discount_10_rate=(NEW.ndis_rate*0.10),
NEW.discount_15_rate=(NEW.ndis_rate*0.15)

answered Aug 1, 2019 at 11:38

Umar Niazi's user avatar

Umar NiaziUmar Niazi

4645 silver badges14 bronze badges

You cannot refer to a table when updating it.

/* my sql does not support this */
UPDATE tableName WHERE 1 = (SELECT 1 FROM tableName)

From MySQL Docs:

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. (Before MySQL 5.0.10, a trigger cannot modify other tables.)

SiHa's user avatar

SiHa

7,63313 gold badges32 silver badges41 bronze badges

answered Jul 20, 2011 at 2:50

BradLaney's user avatar

BradLaneyBradLaney

2,3741 gold badge19 silver badges28 bronze badges

7

The following examples are trying to create triggers to update some data in current table at event AFTER INSERT.

Trigger #1:


CREATE TRIGGER `example1trigger` AFTER INSERT ON `table_name`
FOR EACH ROW
begin
update table_name
set sum = cost * 1.05
where id = NEW.id;
end;

Trigger #2:


CREATE TRIGGER `example2trigger` AFTER INSERT ON `table_name`
FOR EACH ROW
begin
update table_name
set create_date = CURRENT_DATE
where id = NEW.id;
end;

Both triggers will be created successfully, but when we actually insert a row in current table, it will generate an error:

ERROR 1442 (HY000): Can’t update table ‘table_name’ in stored function/trigger because it is already used by statement which invoked this function/trigger.

The truth is that the current trigger is using table «table_name», there is no chance to use it in this invoking procedure.

Since the update statement depends the newly inserted data in Trigger #1, the solution is to abandon the trigger and put both INSERT and UPDATE in a store procedure instead.

It could have another solution for Trigger #2, you can change AFTER INSERT to BEFORE INSERT and simplify the statements like this:


CREATE TRIGGER `example2trigger` BEFORE INSERT ON `table_name`
FOR EACH ROW
begin
set NEW.create_date = CURRENT_DATE;
end;

It runs well without problem in most cases, but it does not guarantee every new row to be successful inserted after all.

For more syntax about triggers, you can refer to the official document: MySQL :: MySQL 5.7 Reference Manual :: 19.3.1 Trigger Syntax and Examples.

While working on MySQL triggers this afternoon, I encountered a strange problem that dealt with using a trigger to tweak records in a table after an UPDATE. Specifically, I wanted to write a trigger that would automatically loop over all records in a table, and then mark any «expired» if they were added more than X days ago. I added a trigger using the UPDATE mechanism I thought would work, but nope, I kept getting this error:

ERROR 1442 (HY000): Can't update table 'pass' in stored
   function/trigger because it is already used by statement
   which invoked this stored function/trigger.

Looks intimidating. According to the MySQL forums, a fairly large number of folks have reported this same problem. Sadly, I wasn’t able to find a good solution to the problem, and according to MySQL’s documentation, what I’m trying to do is damn near impossible with triggers.

What I’m Trying To Accomplish

I’ve got a table named «pass» that contains three fields: an ID field, a status, and a TIMESTAMP. The ID field is simply a unique ID number of some sort. The status field is an ENUM, either «active» or «expired». And, the TIMESTAMP indicates when the record was added to the table. The goal here is to use a trigger that automatically sets the status to «expired» on each row that was added more than 7 days ago. I want to let the MySQL trigger engine take care of managing the expired status of these records for me, so that my web-app doesn’t explicitly have to.

The Schema

Here’s the schema for my «pass» table:

CREATE TABLE pass (
  id BIGINT NOT NULL,
  status ENUM('active','expired') NOT NULL DEFAULT 'active',
  addedon TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY ( id )
) TYPE=InnoDB;

Note that the default value on the status field is «active» and the default on the TIMESTAMP field is the CURRENT_TIMESTAMP (the current time on the MySQL server when the record was added to the table). Let’s add some records to this «pass» table:

mysql> insert into pass ( id ) values ( '1' );
Query OK, 1 row affected (0.00 sec)

mysql> insert into pass ( id ) values ( '2' );
Query OK, 1 row affected (0.00 sec)

mysql> insert into pass ( id ) values ( '3' );
Query OK, 1 row affected (0.00 sec)

mysql> insert into pass ( id ) values ( '4' );
Query OK, 1 row affected (0.00 sec)

mysql> update pass set addedon = '2009-06-30 22:06:03' where id = 3;
Query OK, 1 row affected (0.01 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> select * from pass;
+----+--------+---------------------+
| id | status | addedon             |
+----+--------+---------------------+
|  1 | active | 2009-07-08 22:20:18 |
|  2 | active | 2009-07-08 22:20:19 |
|  3 | active | 2009-06-30 22:06:03 |
|  4 | active | 2009-07-08 22:20:22 |
+----+--------+---------------------+
4 rows in set (0.00 sec)

OK, so I populated the pass table and tweaked the addedon TIMESTAMP of ID 3 so that it’s more than 7 days old. Using a trigger, I want to set the status of this record to «expired» on any UPDATE to the pass table.

The Trigger Problem

The original trigger I wrote used UPDATE pass SET status = 'expired' like so:

DELIMITER |
  CREATE TRIGGER expire_trigger
    BEFORE UPDATE ON pass
    FOR EACH ROW BEGIN
      UPDATE pass SET pass.status = 'expired' WHERE
        (DATEDIFF(NOW(),pass.addedon) > 7);
    END;
|
DELIMITER ;

This looks like it should work, but unfortunately I kept hitting the following error when trying to UPDATE any record in the pass table within the trigger:

ERROR 1442 (HY000): Can't update table 'pass' in stored
   function/trigger because it is already used by statement
   which invoked this stored function/trigger.

In a nutshell the problem here is that I’m trying to use a trigger to UPDATE a table via the operation that invoked the trigger in the first place. According to what I read in the MySQL documentation, this error is generated to prevent infinite recursion: an UPDATE occurs, the trigger is run and updates the table, this trigger UPDATE causes the trigger to run again, and again, and again. Basically without this error, the trigger would trigger itself in an infinite loop.

Trigger Limitations in MySQL

In the end, I concluded that I cannot easily tweak my trigger to accomplish what I’m trying to do. For example, instead of using the UPDATE above, I also tried with procedural like statements:

DELIMITER |
  CREATE TRIGGER expire_trigger
    BEFORE UPDATE ON pass
    FOR EACH ROW BEGIN
      IF (DATEDIFF(NOW(),NEW.addedon) > 7) THEN
        SET NEW.status = 'expired';
      END IF;
    END;
|
DELIMITER ;

This works quite nicely, BUT only on the record that I’m modifying. For example, if I’m updating a record that’s more than 7-days old, then yes, the trigger will change the status to expired for me. However, if I update another record in the table that’s not more than 7-days old, the trigger will not run over ALL records. Basically, it seems that the trigger can only be used to modify/change the record being updated, inserted, or deleted. There does not appear to be a way to write a MySQL trigger that loops over all records when activated.

What About Procedures?

Knowing that triggers won’t let me explicitly loop over and adjust all records in a table on an UPDATE, I gave up and started looking into procedures. A procedure is somewhat similar to a trigger, except that it doesn’t run automatically during an UPDATE, INSERT, DELETE, etc. Instead, the user has to explicitly call a procedure to run it. So, I created a procedure to loop over and expire all records more than 7-days old:

mysql> DELIMITER |
  CREATE PROCEDURE expire_procedure()
    BEGIN
      UPDATE pass SET pass.status = 'expired'
        WHERE (DATEDIFF(NOW(),pass.addedon) > 7);
    END;
|
DELIMITER ;
Query OK, 0 rows affected (0.00 sec)

mysql> CALL expire_procedure();
Query OK, 1 row affected (0.01 sec)

mysql> select * from pass;
+----+---------+---------------------+
| id | status  | addedon             |
+----+---------+---------------------+
|  1 | active  | 2009-07-08 22:20:18 |
|  2 | active  | 2009-07-08 22:20:19 |
|  3 | expired | 2009-06-30 22:06:03 |
|  4 | active  | 2009-07-08 22:20:22 |
+----+---------+---------------------+
4 rows in set (0.00 sec)

Sure enough, the correct record was set to «expired». So, the procedure works fine (I knew it would) but I then tried to call it from a trigger:

mysql> DELIMITER |
  CREATE TRIGGER expire_trigger
    BEFORE UPDATE ON pass
    FOR EACH ROW BEGIN
      CALL expire_procedure();
    END;
|
DELIMITER ;

mysql> update pass set id = 10 where id = 3;
ERROR 1442 (HY000): Can't update table 'pass' in stored
  function/trigger because it is already used by statement
  which invoked this stored function/trigger.

OK, so even using a procedure with a trigger isn’t going to solve my problem. I still see the same error as before.

Conclusion

Bottom line, there doesn’t appear to be a way to use a trigger in MySQL that loops over all rows in a table when activated. And, calling a procedure from a trigger isn’t going to work either. Solutions to this problem might include building your web-app to call your procedure at a given interval. Or, call the procedure when a user logs in (depending on the load). You might even consider using a cron job.

Good luck.

I’m trying to create a hieralchical structure of families, marking the leaf nodes. I have a Trigger to mark the family as a leaf but when I try to save a record the following error happens:

Error Code: 1442. Can't update table 'family' in stored function/trigger because it is already used by statement which invoked this stored function/trigger.

My trigger is:

CREATE TRIGGER MARK_LEAF BEFORE INSERT ON FAMILY FOR EACH ROW
BEGIN
    DECLARE V_IS_LEAF  CHAR(1);

    SELECT IS_LEAF INTO V_IS_LEAF FROM FAMILY WHERE ID = NEW.PARENT_ID;

    IF (V_IS_LEAF = 'F') THEN
        UPDATE FAMILY SET IS_LEAF = 'T' WHERE ID = NEW.PARENT_ID;
    END IF;
END 

Note: family fields are ID, PARENT_ID, IS_LEAF

Note 2: Notice that I always update the parent_id and my structure is hieralchical so there isn’t a loop. Besides, I check if the value is 'F' and I try to change it to 'T', so, if I made a mistake with the parent it only update the same row once.

Is there any way to avoid this error?

Понравилась статья? Поделить с друзьями:

Не пропустите эти материалы по теме:

  • Яндекс еда ошибка привязки карты
  • Ошибка 1441 мицубиси паджеро
  • Ошибка 1440 опель антара
  • Ошибка 144 windows
  • Ошибка 1421 тойота камри 40

  • 0 0 голоса
    Рейтинг статьи
    Подписаться
    Уведомить о
    guest

    0 комментариев
    Старые
    Новые Популярные
    Межтекстовые Отзывы
    Посмотреть все комментарии