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

时间:2018-01-17 17:40:29

标签: mysql mysql-connector

我正在对此进行类似的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()。如果没有插入则返回0,如果插入发生则返回1。查看更多详情here

  

如果执行INSERT ... SELECT语句,则自动执行 NO   生成的值已成功插入,mysql_insert_id() RETURNS   最后插入的行的ID。

如果没有成功插入自动生成的ID,它会返回什么?这是一个文字错字吗?

UPDATE1

到目前为止,我在C中进行了测试,如果即使最后一次插入成功并且mysql_insert_id()返回非零结果也未发生插入,mysql_insert_id()返回始终为0。上面提到的同一手册中的段落通过说:

来证实这种行为
  如果前一个语句不使用AUTO_INCREMENT值,则mysp_insert_id()返回0。 ....

     

mysql_insert_id()的值仅受当前客户端连接中发出的语句的影响。它不受其他客户发布的声明的影响。

     

LAST_INSERT_ID()SQL函数将包含第一个自动生成的值,该值已成功插入。 LAST_INSERT_ID()不会在语句之间重置,因为该函数的值在服务器中维护。 ....

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

UPDATE2

从MariaDB手册中,还建议在未插入的情况下该值应为零:

  

mysql_insert_id()函数返回查询生成的ID   包含具有AUTO_INCREMENT属性或值的列的表   最后一次使用LAST_INSERT_ID(expr)。如果最后一个查询不是   INSERT或UPDATE语句或修改后的表没有   具有AUTO_INCREMENT属性和LAST_INSERT_ID的列不是   使用后,此函数将返回零。

3 个答案:

答案 0 :(得分:3)

措辞可能更清楚,但它意味着如果你的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()将报告批量插入生成的第一个 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 |
+------------------+

同样,即使INSERT成功,但不会导致生成任何新的auto-inc值,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功能自动生成的值。

答案 1 :(得分:2)

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

答案 2 :(得分:1)

看起来它会返回上次自动生成的ID:

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

MariaDB [stackoverflow]> 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 [stackoverflow]> select LAST_INSERT_ID() from dual;
+------------------+
| LAST_INSERT_ID() |
+------------------+
|                2 |
+------------------+
1 row in set (0.00 sec)

MariaDB [stackoverflow]> 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 [stackoverflow]> select LAST_INSERT_ID() from dual;
+------------------+
| LAST_INSERT_ID() |
+------------------+
|                2 |
+------------------+
1 row in set (0.00 sec)