Change LAST_INSERT_ID () from TRIGGER to MySQL

I have a BEFORE INSERT TRIGGER that is used to calculate the value of an AUTO_INCREMENT column ( id_2 ).

 id_1 | id_2 | data 1 | 1 | 'a' 1 | 2 | 'b' 1 | 3 | 'c' 2 | 1 | 'a' 2 | 2 | 'b' 2 | 3 | 'c' 2 | 4 | 'a' 3 | 1 | 'b' 3 | 2 | 'c' 

I have PRIMARY (id_1, id_2) and I am using InnoDB. Previously, MyISAM was used in the table, and I had no problems: id_2 was set to AUTO_INCREMENT , so each new record for id_1 would create a new id_2 its own. Now, after switching to InnoDB, I have this trigger to do the same:

 SET @id = NULL; SELECT COALESCE(MAX(id_2) + 1, 1) INTO @id FROM tbl WHERE id_1 = NEW.id_1; SET NEW.id_2= @id; 

It works fine, except that now LAST_INSERT_ID() has the wrong value (it returns 0). A lot of code depends on the correctness of LAST_INSERT_ID() . However, since MySQL 5.0.12, any changes made to LAST_INSERT_ID inside TRIGGERS do not affect the global value. Is there any way around this? I can easily set AFTER UPDATE TRIGGER , which changes LAST_INSERT_ID by calling LAST_INSERT_ID(NEW.id_2) , however any client side will get LAST_INSERT_ID set to 0.

Is there any work involved to get MySQL to maintain the LAST_INSERT_ID state that was changed inside the trigger? Is there an alternative besides switching to MyISAM that supports this out of the box or runs another SELECT max(id_2) FROM tbl WHERE id_1 = :id as part of the transaction to ensure that the found row is the one that was inserted earlier?

 > SHOW CREATE TABLE tbl; CREATE TABLE `tbl` ( `id_1` int(11) NOT NULL, `id_2` int(11) NOT NULL, `data` varchar(255) COLLATE utf8_unicode_ci NOT NULL, PRIMARY KEY (`id_1`,`id_2`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci 

Example:

 INSERT INTO tbl (id_1, id_2, data) VALUES (1, NULL, 'd'); SELECT LAST_INSERT_ID(); 

The first statement inserts row 1 | 4 | 'd' 1 | 4 | 'd' 1 | 4 | 'd' to the table. The second statement will return 0 , but I need to return 4 .

As requested by Ravinder Reddy , adding a short explanation about the system:

I have a table containing baskets and I have another table ( tbl ) that contains items . The shopping cart application is created by the application and is assigned an identifier from AUTO_INCREMENT in the basket table. The task is to insert elements into the basket with id = id_1 , in tbl , assigning them a unique identifier within this basket. Each element has data associated with it, which can be repeated within the same basket . Therefore, in practice, I try to save all data records within one basket , and then be able to reference (and retrieve) these individual records by their id_1 - id_2 pairs.

+7
mysql triggers auto-increment innodb last-insert-id
source share
1 answer

In his description of the table structure, it is clear that there is no primary key field in it, the values โ€‹โ€‹of which can be generated automatically. MySQL information_schema.tables does not have auto_increment , but null for fields that are not defined by auto_increment .

Trigger Problem :

The code block used in your trigger enclosure seems to depend on the explicit calculation and input for the id fields. He did not use the default behavior for the auto_increment field.

According to MySQL Documentation by LAST_INSERT_ID :

LAST_INSERT_ID () returns BIGINT UNSIGNED (64-bit)
representing the first auto-generated value
inserted successfully for AUTO_INCREMENT column
as a result of the last executed INSERT statement.

It is clear that this is only for the auto_increment fields.
None of the fields id_1 and id_2 are assigned to auto_increment .
Due to the reason, although you pass null as input for these fields when pasting, no value will be automatically generated and assigned to them.

Modify the table to set auto_increment to one of these id_x fields, and then start pasting the values. One caveat is that passing the value explicitly to the auto_increment field during insertion will cause last_insert_id return zero or the most recent automatically generated value, but not NEW.id Passing a null or not selecting the auto_increment field during insertion will generate a NEW value for this field, and last_insert_id can select and return it.

The following example demonstrates the behavior above :

 mysql> drop table if exists so_q27476005; Query OK, 0 rows affected, 1 warning (0.00 sec) mysql> create table so_q27476005( i int primary key ); Query OK, 0 rows affected (0.33 sec) 

The following statement shows the next applicable auto_increment value for the field.

 mysql> select auto_increment -> from information_schema.tables -> where table_name='so_q27476005'; +----------------+ | auto_increment | +----------------+ | NULL | +----------------+ 1 row in set (0.00 sec) 

Let's try to insert a null value in the field.

 mysql> insert into so_q27476005 values( null ); ERROR 1048 (23000): Column 'i' cannot be null 

The error above is because the input was in the not null primary key field, but not related to auto_increment . Only for auto_increment fields can you pass null inputs.

Now let's look at the behavior of last_insert_id :

 mysql> insert into so_q27476005 values( 1 ); Query OK, 1 row affected (0.04 sec) mysql> select last_insert_id(); +------------------+ | last_insert_id() | +------------------+ | 0 | +------------------+ 1 row in set (0.00 sec) 

Since the input was explicit, and also the field was not assigned to auto_increment ,
a call to last_insert_id resulted in a 0 . Note that this may also be some else value if there was another insert call for any other auto_increment field of another table, in the same database connection session.

Let's see the entries in the table.

 mysql> select * from so_q27476005; +---+ | i | +---+ | 1 | +---+ 1 row in set (0.00 sec) 

Now apply auto_increment to field i .

 mysql> alter table so_q27476005 change column ii int auto_increment; Query OK, 1 row affected (0.66 sec) Records: 1 Duplicates: 0 Warnings: 0 

The following statement shows the following applicable value of auto_increment for field i .

 mysql> select auto_increment -> from information_schema.tables -> where table_name='so_q27476005'; +----------------+ | auto_increment | +----------------+ | 2 | +----------------+ 1 row in set (0.00 sec) 

You can cross-check that the parameter last_insert_id still the same.

 mysql> select last_insert_id(); +------------------+ | last_insert_id() | +------------------+ | 0 | +------------------+ 1 row in set (0.00 sec) 

Insert the null value in the i field.

 mysql> insert into so_q27476005 values( null ); Query OK, 1 row affected (0.03 sec) 

This was possible by passing the null to a primary key field because the field is assigned to auto_increment .
Let's see what value was generated and inserted.

 mysql> select last_insert_id(); +------------------+ | last_insert_id() | +------------------+ | 2 | +------------------+ 1 row in set (0.00 sec) 

And the following applicable auto_increment value for field i :

 mysql> select auto_increment -> from information_schema.tables -> where table_name='so_q27476005'; +----------------+ | auto_increment | +----------------+ | 3 | +----------------+ 1 row in set (0.00 sec) mysql> select * from so_q27476005; +---+ | i | +---+ | 1 | | 2 | +---+ 2 rows in set (0.00 sec) 

Now let's see how last_insert_id obtained when an explicit input is specified for the field.

 mysql> insert into so_q27476005 values( 3 ); Query OK, 1 row affected (0.07 sec) mysql> select * from so_q27476005; +---+ | i | +---+ | 1 | | 2 | | 3 | +---+ 3 rows in set (0.00 sec) mysql> select last_insert_id(); +------------------+ | last_insert_id() | +------------------+ | 2 | +------------------+ 1 row in set (0.00 sec) 

You can see that last_insert_id did not commit the value due to explicit input.
But, the information scheme registered the following applicable value.

 mysql> select auto_increment -> from information_schema.tables -> where table_name='so_q27476005'; +----------------+ | auto_increment | +----------------+ | 4 | +----------------+ 1 row in set (0.08 sec) 

Now let's see how last_insert_id obtained when the input for the field is auto / implicit.

 mysql> insert into so_q27476005 values( null ); Query OK, 1 row affected (0.10 sec) mysql> select last_insert_id(); +------------------+ | last_insert_id() | +------------------+ | 4 | +------------------+ 1 row in set (0.00 sec) 

Hope these details help you.

+1
source share

All Articles