我有一个 BEFORE INSERT TRIGGER
用于计算 AUTO_INCREMENT
列的值 ( 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'
我有 PRIMARY(id_1, id_2) 并且我正在使用 InnoDB。之前,该表使用的是 MyISAM,我没有遇到任何问题:id_2
被设置为 AUTO_INCREMENT
,因此 id_1
的每个新条目会生成新的 id_2
在其自己的。现在,在切换到 InnoDB 之后,我有这个触发器来做同样的事情:
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;
它工作得很好,除了现在 LAST_INSERT_ID()
有错误的值(它返回 0)。很多代码依赖于 LAST_INSERT_ID()
是正确的。然而,自 MySQL 5.0.12 以来,对 LAST_INSERT_ID
所做的任何更改在 TRIGGERS 内不影响全局值。有什么办法可以绕过这个吗?我可以轻松设置 AFTER UPDATE TRIGGER
这改变了 LAST_INSERT_ID
调用LAST_INSERT_ID(NEW.id_2)
,但是任何客户端都会得到 LAST_INSERT_ID
设置为 0。
是否有任何可行的解决方法来强制 MySQL 维持 LAST_INSERT_ID
的状态?触发器内部发生了哪些变化?除了切换回支持开箱即用的 MyISAM 或运行另一个 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'
到表中。第二条语句将返回 0
,但我需要它返回 4
.
由 Ravinder Reddy 询问, 添加有关系统的简短说明:
我有一个包含篮子的表,还有另一个包含项目的表(tbl
)。 basket 由应用程序创建并分配了一个来自 AUTO_INCREMENT
的 ID在篮子的 table 上。任务是将 items 插入 id = id_1
的篮子中, 进入 tbl
,在该篮子的范围内为他们分配一个唯一的 ID。每个 item 都有一些 data
与之关联,可能会在同一个篮子中重复。所以在实践中,我试图存储所有 data
单个篮子中的条目,然后能够通过其 id_1
引用(和检索)这些单独的条目- id_2
对。
最佳答案
根据你的表结构描述,很明显它没有可以自动生成值的主键字段。 MySQL 的 information_schema.tables
不保存 auto_increment
值,但对于那些未定义 auto_increment
的字段,null
。
触发问题:
您的触发器主体中使用的代码块似乎取决于 id 字段的显式计算和输入。它没有使用 auto_increment
字段的默认行为。
根据 MySQL's documentation on LAST_INSERT_ID :
LAST_INSERT_ID() returns a BIGINT UNSIGNED (64-bit) value
representing the first automatically generated value
successfully inserted for an AUTO_INCREMENT column
as a result of the most recently executed INSERT statement.
很明显,它仅适用于auto_increment 字段。
id_1
和 id_2
字段都没有属性 auto_increment
。
由于这个原因,尽管您在插入时将 null
作为这些字段的输入传递,但不会自动生成任何值并将其分配给它们。
更改您的表以将 auto_increment
设置为那些 id_x
字段之一,然后开始插入值。一个警告是,在插入期间将值显式传递给 auto_increment
字段将导致 last_insert_id
返回一个 零
或最近自动生成的值,但不会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
。请注意,这也可以是其他值,
如果对另一个表的任何其他 auto_increment
字段有另一个 insert
调用,
在同一个数据库连接 session 中。
让我们看看表中的记录。
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
以下语句显示字段 i
的下一个适用 auto_increment
值。
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)
让我们在字段 i
中插入一个 null
值。
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)
i
字段的下一个适用auto_increment
值是:
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)
希望这些细节对您有所帮助。
关于mysql - 从 MySQL 中的 TRIGGER 中更改 LAST_INSERT_ID(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27476005/