如何获取 MySQL 中最后更新行的 ID?

Posted

技术标签:

【中文标题】如何获取 MySQL 中最后更新行的 ID?【英文标题】:How to get ID of the last updated row in MySQL? 【发布时间】:2010-11-26 03:48:55 【问题描述】:

如何使用 php 获取 mysql 中最后更新行的 ID?

【问题讨论】:

mysqli_insert_id($link) 将准确返回最后更新行的 id。我在我的项目中使用这个功能来达到同样的目的。您可以在同步或异步查询中使用它。只需将 $lastupdated_row_id = mysqli_insert_id($link) 插入您的代码中,它就会为您工作。 如果您更新,您难道不知道该行的 ID 吗?我想一定有一些你不知道的情况。 您可能在更新查询中使用了 where 子句,为什么不能在 select 查询中使用相同的 where 子句? UPDATE foo WHERE bar = 1; SELECT id FROM foo WHERE bar = 1? 【参考方案1】:

我已经找到了这个问题的答案:)

SET @update_id := 0;
UPDATE some_table SET column_name = 'value', id = (SELECT @update_id := id)
WHERE some_other_column = 'blah' LIMIT 1; 
SELECT @update_id;

编辑 aefxx

这种技术可以进一步扩展以检索受更新语句影响的每一行的 ID:

SET @uids := null;
UPDATE footable
   SET foo = 'bar'
 WHERE fooid > 5
   AND ( SELECT @uids := CONCAT_WS(',', fooid, @uids) );
SELECT @uids;

这将返回一个字符串,其中所有 ID 用逗号连接。

【讨论】:

不敢相信这有 0 个赞成票,而 mysql_insert_id() 评论根本不是 OP 所要求的,有 13 个。感谢 Pomyk,一个聪明的把戏! 由于您有一个WHERE 子句,您可以在下一个查询SELECT id FROM footable WHERE fooid > 5 中使用相同的WHERE 子句 这个可能大家都明白,但是如果你用mysql_query();你必须把它分成三个不同的调用,但它会起作用。 甚至不需要使用变量。 LAST_INSERT_ID() 可以接受一个参数,该参数会将下一次调用返回的值设置为 LAST_INSERT_ID()。例如:UPDATE table SET id=LAST_INSERT_ID(id), row='value' WHERE other_row='blah';。现在,SELECT LAST_INSERT_ID(); 将返回更新后的 id。有关详细信息,请参阅 newtover 的答案。 @SteveChilds 我只是在评论 newtover 的问题,并想为您所描述的陷阱添加一个解决方案。如果没有要更新的内容,这会将 LAST_INSERT_ID 设置为 0:UPDATE lastinsertid_test SET row='value' WHERE row='asd' AND LAST_INSERT_ID(id) OR LAST_INSERT_ID(0);。但是它不会检索多个 id,所以这个答案是优越的。【参考方案2】:

嗯,我很惊讶在答案中我没有看到最简单的解决方案。

假设item_iditems 表中的一个整数标识列,并且您使用以下语句更新行:

UPDATE items
SET qwe = 'qwe'
WHERE asd = 'asd';

然后,要知道语句之后最新受影响的行,您应该将语句稍微更新为以下内容:

UPDATE items
SET qwe = 'qwe',
    item_id=LAST_INSERT_ID(item_id)
WHERE asd = 'asd';
SELECT LAST_INSERT_ID();

如果您只需要更新真正更改的行,则需要通过 LAST_INSERT_ID 添加 item_id 的条件更新,检查该行中的数据是否会更改。

【讨论】:

它是多用户安全的,因为多个客户端可以发出 UPDATE 语句并使用 SELECT 语句(或 mysql_insert_id())获取自己的序列值,而不会影响或受其他生成它们的客户端的影响自己的序列值。根据dev.mysql.com/doc/refman/5.0/en/… 这不会将 item_id 设置为最后插入的记录吗? @arleslie,如果您点击上面 brutuscat 评论中的文档链接,您会发现它不会。这正是该案例的预期行为。 这确实是正确答案。虽然查询看起来有点违反直觉,但这正是 MySQL 文档所说的。 如果查询让您感到困惑,因为 LAST_INSERT_ID(expr) 将为 UPDATE 调用返回 expr 的值,您也可以像这样使用它:UPDATE items SET qwe = 'qwe' WHERE asd = 'asd' AND LAST_INSERT_ID(item_id); SELECT LAST_INSERT_ID();【参考方案3】:

这在官方上很简单,但非常违反直觉。如果你正在做:

update users set status = 'processing' where status = 'pending'
limit 1

改成这样:

update users set status = 'processing' where status = 'pending'
and last_insert_id(user_id) 
limit 1

where 子句中添加last_insert_id(user_id) 是告诉MySQL 将其内部变量设置 为找到的行的ID。当您像这样将一个值传递给last_insert_id(expr) 时,它最终会返回该值,在像这里这样的ID 的情况下,它始终是一个正整数,因此总是计算为真,从不干扰 where 子句。这仅在实际找到某些行时才有效,因此请记住检查受影响的行。然后,您可以通过多种方式获取 ID。

MySQL last_insert_id()

您可以在不调用 LAST_INSERT_ID() 的情况下生成序列,但是 以这种方式使用该函数的效用是 ID 值为 作为最后一个自动生成的值保存在服务器中。它 是多用户安全的,因为多个客户端可以发出 UPDATE 语句并使用 SELECT 语句获取自己的序列值 (或 mysql_insert_id()),不影响或受其他 生成自己的序列值的客户端。

MySQL mysql_insert_id()

返回由 AUTO_INCREMENT 列生成的值 以前的 INSERT 或 UPDATE 语句。完成后使用此功能 对包含 AUTO_INCREMENT 字段,或已使用 INSERT 或 UPDATE 设置列 LAST_INSERT_ID(expr) 的值。

LAST_INSERT_ID() 和 mysql_insert_id() 是 LAST_INSERT_ID() 易于使用 mysql_insert_id() 尝试提供更准确的脚本 有关 AUTO_INCREMENT 列发生的情况的信息。

PHP mysqli_insert_id()

使用 LAST_INSERT_ID() 执行 INSERT 或 UPDATE 语句 函数还将修改 mysqli_insert_id() 返回的值 功能。

把它们放在一起:

$affected_rows = DB::getAffectedRows("
    update users set status = 'processing' 
    where status = 'pending' and last_insert_id(user_id) 
    limit 1"
);
if ($affected_rows) 
    $user_id = DB::getInsertId();

(仅供参考DB class is here。)

【讨论】:

需要注意的重要一点:这是多连接安全的,last_insert_id 或 mysql_insert_id 的持久值(可能是 mysqli_insert_id,我没有检查)是每个连接的。太棒了! 这看起来是个不错的解决方案,但是引入了一个我仍然不明白的错误——处理多个条目时,偶尔会跳过返回的 ID 数量,这与原始查询的行为不同那是派生的合并(更新语句中的选择语句)。我不得不恢复它并改为执行两个不同的查询。 @LucasBustamante 你的环境是什么? node-mysql2 连接池中断事务、临时表和 last_insert_id()。解决方法是从池中提取一个连接,对同一连接运行连续查询,然后将连接释放回池中。【参考方案4】:

这与 Salman A 的答案相同,但这是您实际需要执行的代码。

首先,编辑您的表格,以便在修改行时自动跟踪。如果您只想知道最初插入行的时间,请删除最后一行。

ALTER TABLE mytable
ADD lastmodified TIMESTAMP 
    DEFAULT CURRENT_TIMESTAMP 
    ON UPDATE CURRENT_TIMESTAMP;

然后,要找出最后更新的行,您可以使用此代码。

SELECT id FROM mytable ORDER BY lastmodified DESC LIMIT 1;

此代码全部来自MySQL vs PostgreSQL: Adding a 'Last Modified Time' Column to a Table 和MySQL Manual: Sorting Rows。我刚刚组装好了。

【讨论】:

如果第二次插入是在第一次插入查询之后完成的,则此方法可能会获取错误的 id。但是,如果我们在这个查询中使用 'WHERE',即 SELECT id FROM mytable ORDER BY lastmodified DESC LIMIT 1 WHERE(一些与最后插入查询相关的条件),那么它可能会阻止获取错误的 id。 @TheNoble-Coder 这是真的。如果您需要获取影响特定更新查询的行的 id,请使用 Pomyk 的技术。这种技术在异步使用时更有用,您只需要绝对的最后更新。【参考方案5】:

查询:

$sqlQuery = "UPDATE 
            update_table 
        SET 
            set_name = 'value' 
        WHERE 
            where_name = 'name'
        LIMIT 1;";

PHP函数:

function updateAndGetId($sqlQuery)

    mysql_query(str_replace("SET", "SET id = LAST_INSERT_ID(id),", $sqlQuery));
    return mysql_insert_id();

这对我有用;)

【讨论】:

我喜欢相同但运行不同参考:forums.mysql.com/read.php?52,390616,390619【参考方案6】:
SET @uids := "";
UPDATE myf___ingtable
   SET id = id
   WHERE id < 5
  AND ( SELECT @uids := CONCAT_WS(',', CAST(id AS CHAR CHARACTER SET utf8), @uids) );
SELECT @uids;

我必须转换 id(不知道为什么)...否则我无法获取 @uids 内容(它是一个 blob) 顺便说一句,非常感谢 Pomyk 的回答!

【讨论】:

【参考方案7】:

嘿,我只是需要这样一个技巧 - 我以不同的方式解决了它,也许它对你有用。请注意,这不是一个可扩展的解决方案,对于大型数据集非常不利。

将您的查询分成两部分 -

首先,选择要更新的行的 ID 并将它们存储在临时表中。

其次,将更新语句中的条件改为where id in temp_table进行原始更新。

并且为了保证并发,这两个步骤之前需要lock表,然后在最后释放锁。

同样,这对我有用,对于以limit 1 结尾的查询,所以我什至不使用临时表,而只是一个变量来存储第一个select 的结果。

我更喜欢这种方法,因为我知道我只会更新一行,而且代码很简单。

【讨论】:

【参考方案8】:

最后更新行的 ID 与您在“updateQuery”中用于查找和更新该行的 ID 相同。因此,只需保存(调用)该 ID 即可。

last_insert_id() 取决于 AUTO_INCREMENT,但最后更新的 ID 不是。

【讨论】:

如果更新不是从一个 id 而是从另一组属性完成的呢?【参考方案9】:

我的解决方案是,首先使用 select 命令确定“id”(@uids),然后使用 @uids 更新此 id。

SET @uids := (SELECT id FROM table WHERE some = 0 LIMIT 1);
UPDATE table SET col = 1 WHERE id = @uids;SELECT @uids;

它适用于我的项目。

【讨论】:

【参考方案10】:

以上已接受答案的更多信息对于那些想知道 :== 的人

:== 之间的显着区别在于,:= 在任何地方都可以用作变量赋值运算符,而= 只能在 SET 语句中以这种方式工作,并且在其他任何地方都是比较运算符。

所以SELECT @var = 1 + 1; 将保持@var 不变并返回一个布尔值(1 或0 取决于@var 的当前值),而SELECT @var := 1 + 1; 将更改@var2,然后返回 2. [Source]

【讨论】:

嘿,谢谢。他们的意思实际上比上面公认的答案更有趣。【参考方案11】:

如果您只进行插入,并且想要从同一会话中插入,请按照 peirix 的回答进行。如果您正在进行修改,则需要修改数据库架构以存储最近更新的条目。

如果您想要上次修改的 id,它可能来自不同的会话(即不是当前运行的 PHP 代码刚刚完成的,而是响应不同请求而完成的),您可以在您的表中添加一个名为 last_modified 的 TIMESTAMP 列(有关信息,请参阅http://dev.mysql.com/doc/refman/5.1/en/datetime.html),然后在更新时设置 last_modified=CURRENT_TIME。

设置后,您可以使用如下查询: SELECT id FROM table ORDER BY last_modified DESC LIMIT 1; 获取最近修改的行。

【讨论】:

【参考方案12】:

不需要这么长的Mysql代码。在 PHP 中,查询应该是这样的:

$updateQuery = mysql_query("UPDATE table_name SET row='value' WHERE id='$id'") or die ('Error');
$lastUpdatedId = mysql_insert_id();

【讨论】:

以上是关于如何获取 MySQL 中最后更新行的 ID?的主要内容,如果未能解决你的问题,请参考以下文章

如何在没有'id'列的MySql中获取最后插入的记录?

如何在 MySQL 中获取多个插入行的 ID?

是否可以在sql中获取行的最后更新时间

如何在INSERT之前获取mysql行的ID

如何获取行的最后更改时间戳?

如何检查/更新数据库中包含大约百万行的列?