mysql_insert_id() 用于 INSERT...SELECT 语句

mysql_insert_id() for INSERT...SELECT statement

我正在进行类似的 INSERT...SELECT 查询

INSERT INTO table (value1, value2) 
SELECT 'stuff for value1', 'stuff for value2' FROM DUAL
WHERE NOT EXISTS (SELECT * FROM table
      WHERE value1='stuff for value1' AND value2='stuff for value2') 
LIMIT 1 

,其中 table 具有自动生成的 ID。

当然,我想知道它是否已插入。我假设这样做的方法是使用 mysql_insert_id()。它 return 如果没有插入发生则为 0,如果插入发生则为 1。查看更多详细信息 here.

If an INSERT ... SELECT statement is executed, and NO automatically generated value is successfully inserted, mysql_insert_id() RETURNS the ID of the last inserted row.

如果没有成功插入自动生成的 ID,return 会怎样?这是文档拼写错误吗?

更新1

到目前为止,我在 C 中进行了测试并且 mysql_insert_id() return 如果插入没有发生,即使最后一次插入成功并且 mysql_insert_id() returned 不- 零结果。上面提到的同一手册中的一段通过以下内容确认了此行为:

mysql_insert_id() returns 0 if the previous statement does not use an AUTO_INCREMENT value. ....

The value of mysql_insert_id() is affected only by statements issued within the current client connection. It is not affected by statements issued by other clients.

The LAST_INSERT_ID() SQL function will contain the value of the first automatically generated value that was successfully inserted. LAST_INSERT_ID() is not reset between statements because the value of that function is maintained in the server. ....

这感觉有点合乎逻辑,否则 INSERT...SELECT 在许多情况下将毫无用处,如果您无法在代码中知道您的插入是否有效。但这与上面的说法完全矛盾。有人有这方面的经验吗?

更新2

来自 MariaDB 手册,还建议在未发生插入的情况下该值应为零:

The mysql_insert_id() function returns the ID generated by a query on a table with a column having the AUTO_INCREMENT attribute or the value for the last usage of LAST_INSERT_ID(expr). If the last query wasn't an INSERT or UPDATE statement or if the modified table does not have a column with the AUTO_INCREMENT attribute and LAST_INSERT_ID was not used, this function will return zero.

看起来它将 return 上次自动生成的 ID:

MariaDB [Whosebug]> desc a;
+-------+-------------+------+-----+---------+----------------+
| Field | Type        | Null | Key | Default | Extra          |
+-------+-------------+------+-----+---------+----------------+
| id    | int(11)     | NO   | PRI | NULL    | auto_increment |
| a     | varchar(20) | YES  |     | NULL    |                |
| b     | varchar(20) | YES  |     | NULL    |                |
+-------+-------------+------+-----+---------+----------------+
3 rows in set (0.01 sec)

MariaDB [Whosebug]> insert into a(a,b) values('haha', 'haha');
Query OK, 1 row affected (0.03 sec)
MariaDB [Whosebug]> select LAST_INSERT_ID() from dual;
+------------------+
| LAST_INSERT_ID() |
+------------------+
|                1 |
+------------------+

MariaDB [Whosebug]> insert into a(a,b) select 'hi', 'hello' from dual;
Query OK, 1 row affected (0.01 sec)
Records: 1  Duplicates: 0  Warnings: 0

MariaDB [Whosebug]> select LAST_INSERT_ID() from dual;
+------------------+
| LAST_INSERT_ID() |
+------------------+
|                2 |
+------------------+
1 row in set (0.00 sec)

MariaDB [Whosebug]> insert into a(a,b) select 'hi', 'hello' from dual where not exists (select * from a where a='hi' and b='hello') limit 1;
Query OK, 0 rows affected (0.00 sec)
Records: 0  Duplicates: 0  Warnings: 0

MariaDB [Whosebug]> select LAST_INSERT_ID() from dual;
+------------------+
| LAST_INSERT_ID() |
+------------------+
|                2 |
+------------------+
1 row in set (0.00 sec)

措辞可以更清楚,但它的意思是,如果你的 INSERT 导致错误,mysql_insert_id()(或 SQL 函数 last_insert_id())继续报告无论它根据之前的成功 INSERT.

做了什么

这是一个演示:

mysql> create table foo( id int auto_increment primary key);
mysql> create table bar( id int primary key);    
mysql> insert into bar (id) values (1), (2), (10);

mysql> insert into foo select id from bar;

mysql> select last_insert_id();
+------------------+
| last_insert_id() |
+------------------+
|                0 |
+------------------+

没有生成新的 auto-inc 值,因为我的 INSERT 给出了要插入的特定值。

让我们生成一些新值:

mysql> insert into foo select null from bar;
Query OK, 3 rows affected (0.02 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> select last_insert_id();
+------------------+
| last_insert_id() |
+------------------+
|               11 |
+------------------+

这是预期的,因为 last_insert_id() 将报告批量插入生成的 first id。您必须计算出插入了多少行,这样您才能知道其余的 id。这样生成的id保证唯一且连续。

现在让我们尝试插入一些重复项,这会导致错误:

mysql> insert into foo select id from bar;
ERROR 1062 (23000): Duplicate entry '1' for key 'PRIMARY'

现在是文档中句子的重点:last_insert_id() 报告的内容没有变化。

mysql> select last_insert_id();
+------------------+
| last_insert_id() |
+------------------+
|               11 |
+------------------+

同样,即使插入成功,但不会导致生成任何新的自动增量值,last_insert_id() 报告的内容也没有变化。

mysql> insert into foo select id+20 from bar;
Query OK, 3 rows affected (0.02 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> select last_insert_id();
+------------------+
| last_insert_id() |
+------------------+
|               11 |
+------------------+

许多人假设 last_insert_id() 报告了最近插入的主键值,但事实并非如此。它仅报告由 auto-inc 功能自动生成的值。

mysql_affected_rows 是你的朋友。如果您成功插入行,它将大于 0(除非它 returns (my_ulonglong)-1,表示失败)。在你的情况下,因为你最多插入 1 行,你只需要检查它是否返回 1.