在MySQL数据库中跳过ID

时间:2013-07-12 17:22:06

标签: mysql

因此,以某种方式使用名为id的AUTO_INCREMENT字段输入数据时,我发现数据实际上缺少某些行。那就是会有像:

这样的行
 ID   COL1   COL2
2000  data   data
2001  data   data
2003  data   data

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

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

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

编辑:

这不是关于差距如何发生的问题,而是如何解决问题。我向你保证,这个表上没有删除只有其他程序插入。我知道那里肯定有一个bug。问题是如何在我当前的实时系统上修复数据。

4 个答案:

答案 0 :(得分: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 Fiddle Here

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

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

ALTER TABLE mytable AUTO_INCREMENT = 1;

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


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

如果我们只是想检查是否“跳过”任何id值,我们可以使用别名为u的内联视图中的查询(来自上面的UPDATE语句)。我们将UPDATE更改为SELECT,只过滤掉id值与(generate)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

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

答案 1 :(得分:2)

根据您对我的评论的评论,解决方案是简单地重置自动增量列,如下所示:How to reset AUTO_INCREMENT in MySQL?

ALTER TABLE tablename AUTO_INCREMENT = 1

答案 2 :(得分:1)

正如其他人尝试过但未能告诉您的那样,自动增量列中的间隙不是错误,这是正常的行为(它可能发生在像回滚插入那样简单的事情上)。如果您的应用程序因间隙而窒息,那么应用程序就会被窃听。

您不能尝试使您的ID顺序,您必须专注于让您的应用程序正确处理这些差距。

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

答案 3 :(得分:0)

对于问题1:

嗯..您可以做一个简单的查询来计算id的行。像这样:

id在2000年和2003年之间的your_table中选择计数(id);

该查询的结果应返回4。

问题2:

一个简单的alter table自动递增即可。