7

我有一个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 开始,对 TRIGGERS 所做的任何更改LAST_INSERT_ID都不会影响全局值。有没有办法绕过这个?我可以通过调用轻松设置AFTER UPDATE TRIGGER更改,但是任何客户端都将设置为 0。LAST_INSERT_IDLAST_INSERT_ID(NEW.id_2)LAST_INSERT_ID

是否有任何可行的解决方法来强制 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的表,还有另一个包含项目的表 ( ) 。篮子由应用程序创建,并从篮子表中分配一个ID AUTO_INCREMENT。任务是将具有 id = ,的篮子中的项目插入到 中,并在该篮子的范围内为它们分配一个唯一的 ID。每个项目都有一些与之相关的,可能在同一个篮子中重复。所以在实践中,我试图将所有条目存储在一个篮子中,然后能够通过它们的-对来引用(和检索)这些单独的条目。id_1tbldatadataid_1id_2

4

1 回答 1

2

通过您的表结构描述,很明显它没有可以自动生成值的主键字段。MySQLinformation_schema.tables不持有auto_increment价值,但null对于那些未定义的字段auto_increment

触发问题

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

根据MySQL 关于 LAST_INSERT_ID 的文档

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

很明显,它仅适用于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结果为 a 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尽管将 a 传递给了一个字段,但它成功了primary key,因为该字段属于auto_increment.
让我们看看生成并插入了哪个值。

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

该字段的下一个适用auto_incrementi是:

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)

希望,这些细节对你有所帮助。

于 2018-01-20T08:46:18.097 回答