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.tablesdoes not holdauto_incrementvalue butnullfor 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_incrementfield.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_1andid_2are attributedauto_increment.Due to the reason, though you pass
nullas input for those fields while inserting, no value will be auto generated and assigned to them.Alter your table to set
auto_incrementto one of thoseid_xfields, and then start inserting values. One caution is that passing a value explicitly to anauto_incrementfield during insertion will causelast_insert_idreturn azeroor most recent auto generated value, but not theNEW.id. Passing anullor not choosing theauto_incrementfield during insertion will trigger generation of NEW value for that field andlast_insert_idcan pick and return it.Following example demonstrates above behaviour:
Following statement shows next applicable
auto_incrementvalue for a field.Let us try inserting a
nullvalue into the field.Above statement failed because input was into a
not null primary keyfield but not attributed forauto_increment. Only forauto_incrementfields, you can passnullinputs.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_idresulted a0. Note that, this can also be some value else, if there was anotherinsertcall for any otherauto_incrementfield of another table, in the same database connection session.Let us see the records in the table.
Now, let us apply
auto_incrementto the fieldi.Following statement shows next applicable
auto_incrementvalue for the fieldi.You can cross check that the
last_insert_idstill is the same.Let us insert a
nullvalue into the fieldi.It succeeded though passing a
nullto aprimary keyfield, because the field is attributed forauto_increment.Let us see which value was generated and inserted.
And the next applicable
auto_incrementvalue for the fieldiis:Now, let us observe how
last_insert_idresults when explicit input is given for the field.You can see that
last_insert_iddid not capture the value due to explicit input.But, information schema do registered next applicable value.
Now, let us observe how
last_insert_idresults when input for the field is auto/implicit.Hope, these details help you.