我有一个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
对。
答案 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_1
和id_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)
希望,这些细节可以帮助您。