I have a BEFORE INSERT TRIGGER
which is used to calculate the AUTO_INCREMENT
value of a 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. Before, the table was using MyISAM and I've had no problems: id_2
was set to AUTO_INCREMENT
, so each new entry for id_1
would generate new id_2
on its own. Now, after switching to InnoDB, I have this trigger to do the same thing:
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 perfectly, except now the LAST_INSERT_ID()
has wrong value (it returns 0). A lot of code depends on the LAST_INSERT_ID()
being correct. However since MySQL 5.0.12 any changes made to LAST_INSERT_ID
within TRIGGERS are not affecting the global value. Is there any way to bypass this? I can easily set the AFTER UPDATE TRIGGER
which changes the LAST_INSERT_ID
by calling LAST_INSERT_ID(NEW.id_2)
, however any client-side would get LAST_INSERT_ID
set to 0.
Is there any working work-around to force MySQL to maintain the state of LAST_INSERT_ID
which was changed inside the trigger? Is there any alternative, other than switching back to MyISAM which supports this out of the box or running another SELECT max(id_2) FROM tbl WHERE id_1 = :id
as part of the transaction to ensure that the row found will be the one 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 will insert the row 1 | 4 | 'd'
into the table. The second statement will return 0
, but I need it to return 4
.
As asked by Ravinder Reddy, adding the short explanation about the system:
I have a table that contains baskets, and I have another table (tbl
) that contains items. The basket is created by the application and is assigned an ID from AUTO_INCREMENT
on baskets' table. The task is to insert items in basket with id = id_1
, into tbl
, assigning them a unique ID within that basket's scope. Each item has some data
associated with it, which may repeat within the same basket. So in practice, I am trying to store all the data
entries within a single basket, and then be able to refer to (and retrieve) these individual entries by their id_1
-id_2
pairs.
With your table structure description, it is clear that it does not have a primary key field whose values can be auto generated. MySQL's
information_schema.tables
does not holdauto_increment
value butnull
for those fields which are not definedauto_increment
.Trigger issue:
The code block used in your trigger body seems depending on explicit calculation and input for the id fields. It did not use the default behaviour of an
auto_increment
field.As per MySQL's documentation on LAST_INSERT_ID:
It is clear that it is for auto_increment fields only.
None of the fields
id_1
andid_2
are attributedauto_increment
.Due to the reason, though you pass
null
as input for those fields while inserting, no value will be auto generated and assigned to them.Alter your table to set
auto_increment
to one of thoseid_x
fields, and then start inserting values. One caution is that passing a value explicitly to anauto_increment
field during insertion will causelast_insert_id
return azero
or most recent auto generated value, but not theNEW.id
. Passing anull
or not choosing theauto_increment
field during insertion will trigger generation of NEW value for that field andlast_insert_id
can pick and return it.Following example demonstrates above behaviour:
Following statement shows next applicable
auto_increment
value for a field.Let us try inserting a
null
value into the field.Above statement failed because input was into a
not null primary key
field but not attributed forauto_increment
. Only forauto_increment
fields, you can passnull
inputs.Now let us see the behaviour of
last_insert_id
:As the input was explicit and also the field is not attributed for
auto_increment
,call for
last_insert_id
resulted a0
. Note that, this can also be some value else, if there was anotherinsert
call for any otherauto_increment
field of another table, in the same database connection session.Let us see the records in the table.
Now, let us apply
auto_increment
to the fieldi
.Following statement shows next applicable
auto_increment
value for the fieldi
.You can cross check that the
last_insert_id
still is the same.Let us insert a
null
value into the fieldi
.It succeeded though passing a
null
to aprimary key
field, because the field is attributed forauto_increment
.Let us see which value was generated and inserted.
And the next applicable
auto_increment
value for the fieldi
is:Now, let us observe how
last_insert_id
results when explicit input is given for the field.You can see that
last_insert_id
did not capture the value due to explicit input.But, information schema do registered next applicable value.
Now, let us observe how
last_insert_id
results when input for the field is auto/implicit.Hope, these details help you.