Yii2 SQL迁移中记录更新被重复覆盖的问题求助
问题原因分析
你遇到的问题核心是新ID生成逻辑与现有记录ID冲突,且一次性执行批量SQL时,主键修改操作会干扰后续语句:
- 生成的新ID和
card_list表中已有记录的旧ID重复,导致第一个UPDATE覆盖了原有记录; - 后续UPDATE语句的WHERE条件如果匹配到刚修改的新ID(而这个新ID原本是其他记录的旧ID),就会对同一条记录重复修改。
另外,你的代码中拼接SQL时末尾多了一个分号,虽然不影响执行,但属于语法不规范。
解决方法
方案一:确保新ID唯一性+批量执行SQL
先保证新ID不会与现有记录冲突,同时保留旧ID作为WHERE条件,避免后续语句误匹配新ID:
$sql = ''; // 更新card_series表 $sql .= "UPDATE card_series SET Code = 903 WHERE ID = 1600;"; // 查询需要修改的card_list记录,仅获取旧ID(用数组形式避免ActiveRecord对象的潜在问题) $cardOldIds = CardList::find() ->select(['ID']) ->where(['seriesId' => 1600]) ->orderBy('ID') ->asArray() ->all(); // 获取当前card_list表的最大ID,确保新ID从最大值+1开始生成,避免冲突 $maxCardId = CardList::find()->max('ID'); // 如果你需要固定前缀1903,可调整起始值为190300000002或maxCardId+1中的较大值 $startCardNum = max($maxCardId ? $maxCardId + 1 : 190300000002, 190300000002); foreach ($cardOldIds as $item) { $oldId = $item['ID']; $number = str_pad($startCardNum - 190300000000, 8, "0", STR_PAD_LEFT); $newId = $startCardNum; $sql .= "UPDATE card_list SET ID = {$newId}, Code = '903', Number = '{$number}' WHERE ID = {$oldId};"; $startCardNum++; } // 执行批量SQL $this->execute($sql);
方案二:逐条执行UPDATE,避免批处理干扰
放弃批量拼接SQL,逐条执行更新操作,确保每次修改的都是旧ID对应的记录,不会被前面的主键修改影响:
// 先更新card_series表 $this->execute("UPDATE card_series SET Code = 903 WHERE ID = 1600;"); // 查询需要修改的card_list记录 $cardsSeries1600 = CardList::find() ->where(['seriesId' => 1600]) ->orderBy('ID') ->all(); $cardNum = 2; foreach ($cardsSeries1600 as $card) { $number = str_pad($cardNum, 8, "0", STR_PAD_LEFT); $newId = 1903 . $number; // 逐条执行更新,用Yii的参数绑定避免SQL注入风险 Yii::$app->db->createCommand() ->update('card_list', [ 'ID' => $newId, 'Code' => '903', 'Number' => $number, ], ['ID' => $card->ID]) ->execute(); $cardNum++; }
额外注意事项
- 执行迁移前务必备份数据库,避免数据丢失;
- 如果
ID是自增主键,修改后需要手动调整表的自增起始值,比如:ALTER TABLE card_list AUTO_INCREMENT = 新的起始值; - 优先使用Yii的参数绑定方式执行SQL,避免SQL注入风险。
内容的提问来源于stack exchange,提问作者baby
相关产品推荐
相关产品推荐

