为何基于唯一日期生成的ID出现重复?技术求助
问题原因分析
你遇到的重复值问题,核心原因是更新过程中id列的中间态出现了冲突,具体来说:
- 你的循环是按原id从1到356依次处理,每次把当前行的id从
x改成处理后的a。 - 如果某个
a的值正好等于另一个还没被处理的原id(比如a=100,而原id=100的行还没轮到处理),那么当你把原id=x的行改成a后,表中就会同时存在两个id为a的行:一个是刚修改的原x行,另一个是还没处理的原a行。这就直接造成了重复。 - 后续循环到
x=a时,执行select date from archive where id = a会返回两行数据,fetchColumn()只会取第一行的date(大概率是刚修改的那行),然后再次执行update会覆盖原a行的id,进一步导致数据混乱和更多重复。
补充说明:虽然你原date列是唯一的,处理后的a理论上也应该唯一,但中间更新过程的冲突才是导致重复的直接原因,而非a本身重复。
解决方案
最稳妥的方式是基于原始数据一次性完成更新,避免循环中逐步修改id带来的冲突。可以用一条SQL语句直接完成,不需要PHP循环:
UPDATE archive SET id = SUBSTR( REPLACE(REPLACE(REPLACE(date, '-', ''), ' ', ''), ':', ''), 2 )
这条语句会直接对每一行,基于原始的date值计算出目标id,然后一次性更新所有行的id。因为所有更新都是基于原始数据的,不会出现中间态的id冲突。
如果一定要用PHP处理(比如有额外业务逻辑),那也应该先把所有原id和对应的目标id一次性查询出来存储到数组中,再循环执行更新,且更新时要基于原id定位行(而非修改后的id):
// 先一次性获取所有原id和对应的目标id $stmt = $db->query("SELECT id, SUBSTR(REPLACE(REPLACE(REPLACE(date, '-', ''), ' ', ''), ':', ''), 2) AS new_id FROM archive"); $idMap = $stmt->fetchAll(PDO::FETCH_KEY_PAIR); // 循环更新,用原id精准定位行 foreach ($idMap as $oldId => $newId) { $db->query("UPDATE archive SET id = $newId WHERE id = $oldId"); }
这样也能避免中间更新导致的id冲突,因为所有的更新条件都是基于未修改的原id。
内容的提问来源于stack exchange,提问作者qadenza
相关产品推荐
相关产品推荐

