-1

因此,不知何故,在使用名为 id 的 AUTO_INCREMENT 字段输入数据时,我发现数据实际上缺少一些行。那就是会有这样的行:

 ID   COL1   COL2
2000  data   data
2001  data   data
2003  data   data

我的问题不是这种跳过是如何发生的(稍后我将查看我的代码以找到该错误),而是如何找到跳过的行并修复它。所以问题是:

1) 我可以使用什么 SQL 命令来查找跳过的 ID,以便我至少知道它们在哪里?

2) 是否有任何 SQL voodoo 可用于在跳过一个 ID 后向上移动所有行,以便填写缺失的 ID?IE。将行 2003 移动到 2002 和 2004 到 2003 等等

编辑:

这不是差距如何发生的问题,而是如何修复它们的问题。我向您保证,此表上没有删除,仅由另一个程序插入。我知道那里一定有一个错误。问题是如何修复当前活动系统上的数据。

4

4 回答 4

3

auto_increment 列可能具有“跳过”值的原因有多种...插入失败,INSERT IGNORE ...,INSERT ... ON DUPLICATE KEY,插入中指定的值高于下一个值,行插入又删除,一个ALTER TABLE ... AUTO_INCREMENT =语句,有各种原因。

AUTO_INCREMENT 向您保证的是一个独特的价值;它不保证不会跳过任何内容。

通常不需要修改 id 值,如果用户和应用程序(合理地)期望 id 值是不可变的,这可能会给用户和应用程序带来一些重大问题。就数据库而言,请注意外键(由 InnoDB 强制执行,或像 MyISAM 那样隐含但不强制执行)或可能触发的触发器等。

为 ID 列设置新值,以便没有“跳过”值(假设不会违反外键约束)

在此示例中,从 id 2001 之后的 id 值开始,这样下一个更高的 id 值(在您的示例中为 2003)将设置为 2002,之后的下一个更高的 id 值将设置为 2003,依此类推...

UPDATE mytable t 
  JOIN ( SELECT s.id
              , @new_id := @new_id + 1 AS new_id
           FROM ( SELECT @new_id := 2001 ) i
           JOIN ( SELECT r.id
                   FROM mytable r
                  WHERE r.id > 2001
                  ORDER BY r.id
                ) s
          ORDER BY s.id
       ) u
    ON t.id = u.id
   SET t.id = u.new_id

SQL小提琴在这里

同样,所有“跳过”值的警告都不是问题,并且重置 id 值可能会导致大问题(如上所述)适用。

要重置表的 AUTO_INCREMENT 值,只需一个简单的 ALTER TABLE 语句。如果您尝试将其设置为低于最大 id 值,MySQL 将使用最大 id 值。所以,你可以

ALTER TABLE mytable AUTO_INCREMENT = 1;

此语句不会更改现有行,它只是将自动增量值设置为最小值,这样检索到的下一个自动增量将比表中当前的最大 id 值高一个。


要回答您的第一个问题,获取“跳过”的 id 值列表比较困难,因为它们没有行源。

如果我们只想检查是否有任何 id 值被“跳过”,我们可以使用别名为 u 的内联视图中的查询(来自上面的 UPDATE 语句)。我们将该 UPDATE 更改为 SELECT,并仅过滤掉 id 值与(生成)new_id 值匹配的行:

SELECT u.*
  FROM ( SELECT s.id
              , @new_id := @new_id + 1 AS new_id
           FROM ( SELECT @new_id := 2001 ) i
           JOIN ( SELECT r.id
                   FROM mytable r
                  WHERE r.id > 2001
                  ORDER BY r.id
                ) s
          ORDER BY s.id
       ) u
WHERE u.id <> u.new_id
ORDER BY u.id

如果该查询没有返回任何行,则没有“跳过”值。

于 2013-07-12T17:39:08.840 回答
2

根据您对我的评论的评论,一个解决方案是简单地重置自动增量列,如下所示:如何在 MySQL 中重置 AUTO_INCREMENT?

ALTER TABLE tablename AUTO_INCREMENT = 1
于 2013-07-12T17:29:09.013 回答
1

正如其他人尝试并未能告诉您的那样,自动增量列中的间隙不是错误,而是正常行为(它可能发生在像回滚插入这样微不足道的事情上)。如果您的应用程序因间隙而阻塞,则该应用程序存在错误。

您不能试图让您的 ID 连续,您必须专注于让您的应用程序正确处理这些间隙。

如果您绝对需要这些值是连续的,那么您根本不应该使用自动增量列(或者添加手工制作的order列,也许)。

于 2013-07-12T17:40:39.090 回答
0

对于问题 1:

嗯..你可以做一个简单的查询来计算id的行数。就像是:

从2000年到 2003 年之间选择 COUNT( id) ;your_tableid

从那个查询中,结果应该返回 4。

对于问题 2:

一个简单的 alter table auto increment 就可以了。

于 2020-10-26T02:42:12.080 回答