从MySQL插入查询中获取新记录的主键ID?

411

假设我在对我的一个表执行MySQL INSERT 操作,表中有一个名为item_id的列,该列被设置为autoincrementprimary key

如何在同一查询中获取新生成的主键item_id的值?

目前我正在运行第二个查询来检索id,但这似乎不是很好的做法,因为这可能会产生错误的结果...

如果不可能,那么确保检索到正确的id的最佳实践是什么?


9
如果由两个人分别执行该过程,那么我认为你可能会得到一个重叠的过程列表 - 因为你必须执行两个单独的查询? - Amy Neville
@JimFell 是的,基本上是同一个问题,但这个问题的答案普遍更好。 - RozzA
1
使用 PostgreSQL 时,请按如下方式操作: INSERT INTO table (col1,col2) VALUES (val1,val2) RETURNING id 或者 INSERT INTO table (col1,col2) VALUES (val1,val2) RETURNING * 或者 UPDATE table SET col1=val1, col2=val2 WHERE statement RETURNING id 或者 UPDATE table SET (col1,col2)=(val1,val2) WHERE statement RETURNING id 或者 UPDATE table SET (col1,col2)=(val1,val2) WHERE statement RETURNING * - gdarcan
13个回答

516

您需要使用LAST_INSERT_ID()函数:http://dev.mysql.com/doc/refman/5.0/en/information-functions.html#function_last-insert-id

例如:

INSERT INTO table_name (col1, col2,...) VALUES ('val1', 'val2'...);
SELECT LAST_INSERT_ID();

使用此代码可以获取插入的最后一行的PRIMARY KEY值:

生成的ID在服务器上以每个连接为基础进行维护。这意味着该函数返回给定客户端的值是由该客户端最近影响到AUTO_INCREMENT列的大多数最新语句生成的第一个AUTO_INCREMENT值。

因此,LAST_INSERT_ID()返回的值是针对每个用户的,并且不受其他正在运行的来自其他用户的查询的影响。


20
但如果在进程列表查询之间,插入了其他行,该怎么办?有没有办法编写插入查询语句来输出这种情况? - Amy Neville
75
这将使你恢复最后插入的“主键(PRIMARY KEY)”值,因为它是基于每个连接的 - 每个连接到服务器的会话将维护自己的值。我已经更新了答案以澄清这一点。 - Duncan Lock
1
假设有3个用户同时发布了他们的表单,我的数据库必须将它们输入。我想在table2中为每个新创建的table1 ID添加一行。并发是否已经处理好了,还是我需要手动在PHP中处理传入的数据库写请求? - bad_keypoints
如果在进行table1插入时,数据库已经知道您要插入table2的所有信息,则可以使用触发器来完成此操作,或将其合并到查询中。 如果不是这样,那么您需要使用多个查询 - 即在PHP中完成它。 第二次插入取决于数据是什么以及它来自哪里。 - Duncan Lock
1
@DuncanLock,非常正确 - 我感谢您的参考。我只是在评论同时执行插入和ID选择的请求。 - Keiron Stoddart
显示剩余7条评论

37

小心!!使用LAST_INSERT_ID()在PHP中返回主键值。

我知道这个帖子没有标记PHP,但是对于任何想要从使用标准的mysql_query调用的PHP脚本插入中返回MySQL插入id的人来说,它不起作用,并且如果不捕获SQL错误,则不明显。

更新的mysqli支持多个查询,其中LAST_INSERT_ID()实际上是从原始查询中派生的第二个查询。

在我看来,通过单独的SELECT来识别最后一个主键比可选的mysql_insert_id()函数更安全,后者返回上一个INSERT操作生成的AUTO_INCREMENT ID


14
LAST_INSERT_ID 是一个基于连接的 MySQL 函数。如果你查询最后插入的 ID,那么在此期间,可能有另外一个连接已经执行了写操作,导致你获得错误的 ID。为了避免这种情况,需要确保在同一连接中查询最后插入的 ID。 - Explosion Pills
@ExplosionPills mysql_insert_id() 也是基于每个连接的,但它也会出现奇怪的行为,如 Cliffordlife 在这里的评论中所见 https://dev59.com/VXNA5IYBdhLWcg3wmfK5#897374 -- 不过没关系,我们都应该使用 mysqli - RozzA
2
当你说“它不起作用”时,你能否澄清一下你的意思? - john k

27

根据 LAST_INSERT_ID() 的文档:

生成的ID是基于 每个连接 在服务器上进行维护的。

也就是说,如果您同时有两个独立的请求发送到脚本,它们不会影响彼此的 LAST_INSERT_ID() (除非您可能正在使用持久连接)。


3
如果你的表上有一个触发器会向另一个表插入数据,我认为这是值得怀疑的...LAST_INSERT_ID()将会返回另一个表中的id值。 - bgies

27

您将在查询结果中收到这些参数:

    "fieldCount": 0,
    "affectedRows": 1,
    "insertId": 66,
    "serverStatus": 2,
    "warningCount": 1,
    "message": "",
    "protocol41": true,
    "changedRows": 0
< p > insertId 就是你所需要的东西。 < /p > < p > (NodeJS-mysql) < /p >

24

这里是你正在寻找的东西!!!

select LAST_INSERT_ID()

这是在SQL Server中使用SCOPE_IDENTITY()函数的最佳替代方案。

请记住,只有在您的Insert查询之后触发Last_INSERT_ID()时,它才能正常工作。也就是说,查询返回了插入模式中的ID。您无法获取特定表的最后插入的ID。

有关更多详细信息,请查看链接The equivalent of SQLServer function SCOPE_IDENTITY() in mySQL?


21

如果在Python中使用pymysql,你可以从游标中使用cursor.lastrowid

这是一个PEP-249文档扩展中有记录的DB API标准,并且也适用于其他Python MySQL实现。


6
伙计,你的这条评论真是太棒了,你应该得到一枚奖牌。这篇帖子是今天发生的最好的事情。 - DeadSec

20

我本以为这应该是被接受的答案。事务可能并非必要,但在我看来,这似乎是最安全和最清晰的方法。 - Thomas Fox
这个问题的唯一安全、专业和正确的答案。 - Yasser CHENIK

10

只需使用以下代码:

$last_id = mysqli_insert_id($conn);

3
我其实是通过谷歌搜索这个答案的 PHP 版本而偶然来到这里的,所以我给这个答案点了赞。虽然 OP 没有明确要求 PHP 版本,但这对于很多也是偶然来到这里的人可能会有所帮助。 - Photographer Britt
非常感谢你,Arnav! - JuanSedano

5
如果您需要在插入行之前获取值:
CREATE FUNCTION `getAutoincrementalNextVal`(`TableName` VARCHAR(50))
    RETURNS BIGINT
    LANGUAGE SQL
    NOT DETERMINISTIC
    CONTAINS SQL
    SQL SECURITY DEFINER
    COMMENT ''
BEGIN

    DECLARE Value BIGINT;

    SELECT
        AUTO_INCREMENT INTO Value
    FROM
        information_schema.tables
    WHERE
        table_name = TableName AND
        table_schema = DATABASE();

    RETURN Value;

END

您可以在插入操作中使用以下代码:

INSERT INTO
    document (Code, Title, Body)
VALUES (                
    sha1( concat (convert ( now() , char), ' ',   getAutoincrementalNextval ('document') ) ),
    'Title',
    'Body'
);

5
这个想法似乎不太好?如果两个客户端同时调用该函数,它们会认为插入相同的ID,但实际上并非如此...其中一个会稍慢地插入并获取下一个ID,而不知道已经有另一个客户端插入了相同的ID。 - CarCar

4
如果您使用PHP:在PDO对象上,您可以在插入后简单地调用lastInsertId方法。
否则,使用LAST_INSERT_ID,您可以像这样获取值:SELECT LAST_INSERT_ID();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接