You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Yii2 SQL迁移中记录更新被重复覆盖的问题求助

问题原因分析

你遇到的问题核心是新ID生成逻辑与现有记录ID冲突,且一次性执行批量SQL时,主键修改操作会干扰后续语句:

  1. 生成的新ID和card_list表中已有记录的旧ID重复,导致第一个UPDATE覆盖了原有记录;
  2. 后续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++;
}
额外注意事项
  1. 执行迁移前务必备份数据库,避免数据丢失;
  2. 如果ID是自增主键,修改后需要手动调整表的自增起始值,比如:
    ALTER TABLE card_list AUTO_INCREMENT = 新的起始值;
    
  3. 优先使用Yii的参数绑定方式执行SQL,避免SQL注入风险。

内容的提问来源于stack exchange,提问作者baby

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 21:07:44