MySQL修复了两个表中的自动增量空白

Emp*_*ger 5 php mysql database auto-increment

我有两张桌子;

id_image   foo    bar
1          3      5
2          8      1
3          17     88
7          14     23
8          12     9


id_image   bar    foo
1          2      3
1          5      6
2          18     11
2          10     12
3          8      21
3          17     81
7          29     50
7          1      14
8          10     26
8          27     34
Run Code Online (Sandbox Code Playgroud)

id_image第一张表中的自动增量存在差距.在第二个表中,id_image引用id_image第一个表中的每个ID,其中有两个ID.

注意:这个表是理论上的.我不知道其中的差距是完全,或无论是否有甚多的差距.我所知道的是第一个值是1,最后一个值高于总行数.

现在,我想解决这个问题.

在你说差距无关紧要之前,如果他们这样做,这是糟糕的数据库设计,让我告诉你; 我同意你的看法.

但是,我正在处理的是一个(绝望的后端倒退)第三方开源系统,我需要将大量现有数据导入到多个表中,这些数据没有交叉引用的ID.我可以确保相同的数据在整个系统的每个表中获得匹配ID的唯一方法是按顺序输入它,这意味着我不能有间隙.

所以我现在需要做的是;

  1. 修复id_image第一个表中列的间隙,以便最后一个值与行计数匹配.
  2. 编辑id_image第二个表中的列,使其值对应于相同的行对应于间隙修复之前.

我该如何开始这样做?我知道这可能超出了MySQL查询语言的功能,因此PHP答案也是可以接受的.谢谢!:)

Bai*_*ker 1

这里的基本思想是首先找到所有的间隙,以确定每个 id 需要减少多少。然后,您必须迭代两个表并应用减量。(您需要添加:主机、数据库、用户、通行证和实际的表名称)

try {
    $pdo = new PDO('mysql:host=HOST;dbname=DB', 'user', 'pass');

    $pdo->beginTransaction();

    // Iterate through all id's in the first table
    $stmt = $pdo->exec('SELECT image_id FROM TableOne ORDER BY image_id ASC');
    $stmt->bindColumn('image_id', $id);

    if(!$stmt->fetch(PDO::FETCH_BOUND)) {
        throw Exception('No rows in table');
    }

    $lastId = $id;
    $gaps = array();

    // Find all the gaps
    while($stmt->fetch(PDO::FETCH_BOUND)) {
        if($id != ($lastId + 1)) {
            $gaps[] = $id;
        }

        $lastId = $id;
    }


    if(!isset($gaps[0])) {
        throw new Exception('No gaps found');
    }

    // For each gap, update the range from the last gap to that gap by subtracting
    // the number of gaps there has been from the id
    $lastGap = $gaps[0];

    for($i = 1; $i < count($gaps); $i++) {
        $stmt = $pdo->prepare('UPDATE TableOne SET image_id = image_id - :i WHERE image_id BETWEEN :lastGap AND :gap');
        $stmt->execute(array(
            ':i' => $i,
            ':lastGap' => $lastGap,
            ':gap' => $gaps[$i]
        ));

        $stmt = $pdo->prepare('UPDATE TableTwo SET image_id = image_id - :i WHERE image_id BETWEEN :lastGap AND :gap');
        $stmt->execute(array(
            ':i' => $i,
            ':lastGap' => $lastGap,
            ':gap' => $gaps[$i]
        ));

        $lastGap = $gaps[$i];
    }

    // Finally, fix the gap between the last found gap and the end of the table
    $stmt = $pdo->prepare('UPDATE TableOne SET image_id = image_id - :i WHERE image_id BETWEEN :lastGap AND :gap');
    $stmt->execute(array(
        ':i' => $i,
        ':lastGap' => $lastGap,
        ':gap' => $gaps[$i]
    ));

    $stmt = $pdo->prepare('UPDATE TableTwo SET image_id = image_id - :i WHERE image_id BETWEEN :lastGap AND :lastId');
    $stmt->execute(array(
        ':i' => $i,
        ':lastGap' => $lastGap,
        ':lastId' => $lastId
    ));

    // Verify everything is correct
    $stmt = $pdo->exec('SELECT image_id FROM TableOne ORDER BY image_id ASC');
    $stmt->bindColumn('image_id', $id);

    if(!$stmt->fetch(PDO::FETCH_BOUND)) {
        throw new Exception('No rows'); // Should never be thrown
    }

    $lastId = $id;

    while($stmt->fetch(PDO::FETCH_BOUND)) {
        if($id != ($lastId + 1)) {
            throw new Exception('There was an error between ids ' . $lastId . ' and '. $id);
        }

        $lastId = $id;
    }

    $stmt = $pdo->exec('SELECT image_id FROM TableTwo ORDER BY image_id ASC');
    $stmt->bindColumn('image_id', $id);

    if(!$stmt->fetch(PDO::FETCH_BOUND)) {
        throw new Exception('No rows in table two'); // Shouldn't hit this
    }

    $lastId = $id;
    $ids = array($id);

    while($stmt->fetch(PDO::FETCH_BOUND)) {
        $ids[] = $id;

        if(count($ids) == 2) {
            if($ids[0] !== $ids[1]) {
                throw new Exception('Table two error on ids ');
            }

            if($ids[0] !== $lastId) {
                throw new Exception('Table two error on id gapfix');
            }

            $lastId = $ids[0];
            $ids = array();
        }
    }

    $pdo->commit();
} catch(Exception $e) {
    $pdo->rollBack();

    var_dump($e);
}
Run Code Online (Sandbox Code Playgroud)

重要的: 您可能希望将其放入文件中并通过 CLI 运行:并在返回所有 id 列表php -f gapfix.php之前包含一个查询,以便您可以验证操作是否按预期工作。$pdo->commit()如果没有,您可以将其回滚,就像什么都没发生一样。 现在,代码会自行检查第一个表的顺序是否正确。然而它还没有检查第二个表。 所有检查均已落实!