如何获取 MySQL 中最后更新行的 ID?
Posted
技术标签:
【中文标题】如何获取 MySQL 中最后更新行的 ID?【英文标题】:How to get ID of the last updated row in MySQL? 【发布时间】:2010-11-26 03:48:55 【问题描述】:【问题讨论】:
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_id
是items
表中的一个整数标识列,并且您使用以下语句更新行:
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;
将更改@var
为2,然后返回 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?的主要内容,如果未能解决你的问题,请参考以下文章