改变MySQL中TRIGGER中的LAST_INSERT_ID()

时间:2014-12-15 01:02:14

标签: mysql triggers innodb auto-increment last-insert-id

我有一个BEFORE INSERT TRIGGER,用于计算列AUTO_INCREMENT的{​​{1}}值。

id_2

我有PRIMARY(id_1,id_2),我正在使用InnoDB。以前,该表使用的是MyISAM并且我没有遇到任何问题: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' 设置为id_2,因此AUTO_INCREMENT的每个新条目都会生成新的id_1它自己的。现在,在切换到InnoDB后,我有这个触发器做同样的事情:

id_2

它完美无缺,但现在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; 的值不正确(它返回0)。很多代码都取决于LAST_INSERT_ID()是否正确。但是,自MySQL 5.0.12起,对TRIGGERS中的LAST_INSERT_ID()所做的任何更改都不会影响全局值。有没有办法绕过这个?我可以通过调用LAST_INSERT_ID轻松设置更改AFTER UPDATE TRIGGER的{​​{1}},但是任何客户端都会将LAST_INSERT_ID设置为0。

是否有任何工作方法可以强制MySQL维持触发器内部更改的LAST_INSERT_ID(NEW.id_2)状态?有没有其他选择,除了切换回支持开箱即用的MyISAM或在事务中运行另一个LAST_INSERT_ID以确保找到的行将是之前插入的那个?

LAST_INSERT_ID

示例:

SELECT max(id_2) FROM tbl WHERE id_1 = :id

第一个语句会将行> 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 插入表中。第二个语句将返回INSERT INTO tbl (id_1, id_2, data) VALUES (1, NULL, 'd'); SELECT LAST_INSERT_ID(); ,但我需要它返回1 | 4 | 'd'

正如Ravinder Reddy所述,添加有关系统的简短说明:

我有一个包含 baskets 的表格,我有另一个包含项目的表格(0)。 购物篮由应用程序创建,并在篮子上分配4的ID'表。任务是将带有id = tbl的购物篮中的商品插入AUTO_INCREMENT,并在该购物篮的范围内为其分配唯一ID。每个都有一些id_1与之关联,可以在同一个购物篮中重复。所以在实践中,我试图将所有tbl条目存储在一个购物篮中,然后能够通过data引用(并检索)这些单独的条目 - data对。

1 个答案:

答案 0 :(得分:1)

使用表结构描述,很明显它没有可以自动生成其值的主键字段。对于那些未定义information_schema.tables的字段,MySQL的auto_increment不保留null值,auto_increment

触发问题

触发器主体中使用的代码块似乎取决于id字段的显式计算和输入。它没有使用auto_increment字段的默认行为。

根据MySQL's documentation on LAST_INSERT_ID

  

LAST_INSERT_ID()返回BIGINT UNSIGNED(64位)值
  表示第一个自动生成的值   已成功插入 AUTO_INCREMENT 列   作为最近执行的INSERT语句的结果。

很明显,仅适用于 auto_increment 字段 id_1id_2字段均未归属auto_increment 由于这个原因,虽然您在插入时将null作为这些字段的输入传递,但不会自动生成任何值并将其分配给它们。

更改您的表格以将auto_increment设置为其中一个id_x字段,然后开始插入值。一个警告是,在插入过程中将值明确传递给auto_increment字段会导致last_insert_id返回zero或最近自动生成的值,但不会返回NEW.id。在插入过程中传递null或不选择auto_increment字段会触发为该字段生成新值,last_insert_id可以选择并返回该字段。

以下示例演示了上述行为

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)

以下语句显示字段的下一个适用auto_increment值。

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

让我们尝试在字段中插入null值。

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

上述语句失败,因为输入属于not null primary key字段,但未归入auto_increment。仅适用于auto_increment字段,您可以传递null个输入。

现在让我们看看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)

由于输入是明确的,而且该字段未归因于auto_increment
致电last_insert_id会产生0。请注意,这也可能是其他值, 如果对另一个表的任何其他insert字段进行了另一次auto_increment调用, 在同一个数据库连接会话中。

让我们看一下表中的记录。

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

现在,让我们将auto_increment应用于字段i

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

以下语句显示字段auto_increment的下一个适用i值。

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

您可以交叉检查last_insert_id是否仍然相同。

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

我们在null字段中插入i值。

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

虽然将null传递给primary key字段但成功了 因为该字段归因于auto_increment 让我们看看生成和插入了哪个值。

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

字段auto_increment的下一个适用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)

现在,让我们观察在为字段提供显式输入时last_insert_id的结果。

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)

您可以看到last_insert_id由于显式输入而未捕获值 但是,信息模式确实注册了下一个适用的值。

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

现在,让我们观察当字段的输入是自动/隐式时last_insert_id的结果。

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)

希望,这些细节可以帮助您。