MySQL中删除后自动增量

Posted

技术标签:

【中文标题】MySQL中删除后自动增量【英文标题】:Auto Increment after delete in MySQL 【发布时间】:2011-01-13 22:08:47 【问题描述】:

我有一个 mysql 表,它的主键字段启用了 AUTO_INCREMENT。 在这里阅读其他帖子后,我注意到人们有同样的问题和不同的答案。一些人建议不要使用此功能,另一些人则表示无法“修复”。

我有:

table: course
fields: courseID, courseName

示例:表中的记录数:18。如果我删除记录 16、17 和 18 - 我希望输入的下一条记录的 courseID 为 16,但是它将是 19,因为最后输入的 courseID 是 18 .

我的 SQL 知识并不令人惊奇,但无论如何可以通过查询(或 phpMyAdmin 界面中的设置)刷新或更新此计数?

此表将与数据库中的其他表相关。


鉴于所有建议,我决定忽略这个“问题”。我将简单地删除和添加记录,同时让自动增量完成它的工作。我想数字是多少并不重要,因为它仅用作唯一标识符并且没有(如上所述)业务含义。

对于那些我可能对我的原始帖子感到困惑的人:我不想使用这个字段来知道我有多少记录。我只是希望数据库看起来整洁并具有更多的一致性。

【问题讨论】:

如果您只删除记录 16 会发生什么? 好点!我应该提到的。理想情况下,将所有内容上移一个? 我遇到的问题在某种程度上与您的问题相反。换句话说,我有一个ENTITY 表和一个ENTITY_LOG 表。每次我从ENTITY 表中插入、更新或删除某些内容时,我都会将该活动与实体的Id 一起记录到ENTITY_LOG 表中。最近有用户删除了ENTITY表中的一堆条目;并在日志表中创建了相应的日志条目。今天,当另一个用户尝试在ENTITY 表中添加新条目时,生成的Id 恰好与之前删除的实体相同!我使用 JdbcTemplate 和 InnoDB。 @WebUser 我不明白为什么会这样。我很确定(并且期望)MySQL 会处理所有这些。不确定 JdbcTemplate 方面的事情 - 也许那里有什么东西在做它(?)。祝你好运! @OmidTahouri,我完全同意这一点。这当然是一个奇怪的问题。因此,我将尝试复制问题并逐步执行代码。感谢您的确认! 【参考方案1】:

您尝试做的事情听起来很危险,因为这不是 AUTO_INCREMENT 的预期用途。

如果您真的想找到最低的未使用密钥值,请不要使用AUTO_INCREMENT,并手动管理您的密钥。但是,这不是推荐的做法。

退一步问“为什么需要回收键值?” unsigned INT(或BIGINT)没有提供足够大的键空间吗?

在您的应用程序生命周期中,您真的会拥有超过 18,446,744,073,709,551,615 的唯一记录吗?

【讨论】:

你是对的。最好忽略它。考虑到这只是一个任务,我不会进入大量数字并且生命周期很短。 出于多种原因同意高度危险。一,在多用户系统中,您每秒可能有许多、数百、数千次更新,并且尝试重写 auto inc 可能会减慢系统速度或损害系统。另外两个开发人员可能不知道您正在这样做,并通过 id 链接记录从而破坏系统。等 好点。答案让我三思而后行。我一直在寻找 auto_incr 中的空白。因为我打算以某种方式循环遍历这些 ID。但我想最好只循环遍历行:) 所以根本不可能?希望在测试环境中执行此操作是有正当理由的。 当然是可能。 MySQL有schema,但对schema的理解并不丰富。语义是在应用程序中派生的。你有整数。不是教室标识符。它没有关于语义是什么的概念,你用它做什么,它如何与其他实体连接,外键不能在数据库之外应用于其他数据结构。因此,“使密钥集合理化”的想法在 MySQL 中并不是一个概念:这将属于应用程序的领域,但尝试这样做几乎总是一个坏主意。【参考方案2】:
ALTER TABLE foo AUTO_INCREMENT=1

如果您已删除最近的条目,则应将其设置为使用下一个可用的最低条目。如中,只要没有 19,删除 16-18 将重置自动增量以使用 16。


编辑:我错过了关于 phpmyadmin 的内容。你也可以在那里设置它。转到表格屏幕,然后单击操作选项卡。那里有一个 AUTOINCREMENT 字段,您可以手动将其设置为您需要的任何内容。

【讨论】:

OP 可以这样做,但他不应该这样做。鉴于 OP 正在尝试做的事情,你应该重新考虑这个建议。 我不该告诉他如何布置他的数据库,或者如何做他的业务逻辑。他还在帖子中提到,他读过其他帖子/页面说这是一个坏主意,所以他知道这不是推荐的做法,但无论如何都会继续这样做。 这是目前对提问者唯一明确的问题提供的最直接的答案。不涉及“建议”。 始终是一个很好的“实践”,但如果您有理由反对它,OP 可能会错过,建议不要使用您的解决方案。 虽然这 一种不好的做法,但它是最好的答案,因为它实际上回答了 OP 的要求【参考方案3】:

数据库中的主自动增量键用于唯一标识给定行,不应赋予任何业务含义。所以保留主键并添加另一列,例如courseOrder。然后,当您从数据库中删除一条记录时,您可能需要发送一条额外的 UPDATE 语句,以减少所有 courseOrder 大于您当前删除的行的 courseOrder 列。

作为旁注,您永远不应该修改关系数据库中主键的值,因为可能有其他表将其作为外键引用,并且修改它可能会违反引用约束。

【讨论】:

他希望保持计数,而不是排序。 UPDATE 似乎没有必要。 好吧,如果他希望保持计数,则无需添加其他列。简单的 count 聚合函数就可以完成这项工作。 好的,谢谢。在这么短的时间内有很多答案/cmets! :O 我正在尝试将它们全部纳入。我将研究计数功能:)【参考方案4】:

试试:

SET @num := 0;

更新 your_table SET id = @num := (@num+1);

ALTER TABLE tableName AUTO_INCREMENT = 1;

这将重置自动递增的值,然后在为其创建新值时计算每一行。

示例:之前

1:这里的第一个值 2:这里的第二个值 X : 删除值 4:表格的其余部分 5 : 其余的..

所以表格将显示数组:1,2,4,5

例子:AFTER(如果你使用这个命令你会得到)

1:这里的第一个值 2:这里的第二个值 3:表格的其余部分 4 : 其余部分

删除的值没有任何痕迹,其余的递增值继续使用这个新计数。

但是

    如果您的代码中某处使用了自动增量值...也许这种归因会导致问题。 如果您不在代码中使用此值,一切都应该没问题。

【讨论】:

如果你想保留旧值并将 auto_increment 设置为最大值,那么你需要找到最大值: 1. 通过排序,取最后一行的值/ 2. 然后在您的代码中将自动增量设置为该最大值 +1。 真的很感激。它对解决我朋友的问题有很大帮助。在互联网上进行了大量搜索后,我找到了这个答案。【参考方案5】:

您不应该依赖 AUTO_INCREMENT id 来告诉您表中有多少条记录。您应该使用SELECT COUNT(*) FROM course。 ID 用于唯一标识课程并可用作其他表中的参考,因此您不应重复 ID,也不应寻求重置自动增量字段。

【讨论】:

我认为他认为这是某种错误。 MySQL 已经 20 岁了。这绝对不是疏忽。自动增量不回收密钥是有充分理由的。你是完全正确的迈克。【参考方案6】:

我来这里是为了寻找标题问题"MySQL - Auto Increment after delete" 的答案,但我只能在问题中找到答案

How to delete certain row from mysql table? How to reset AUTO_INCREMENT in MySQL?

通过使用类似的东西:

DELETE FROM table;
ALTER TABLE table AUTO_INCREMENT = 1;

注意Darin Dimitrov's answer 解释得非常好AUTO_INCREMENT 和它的用法。在做你可能会后悔的事情之前先看看那里。

PS:问题本身更多的是"Why you need to recycle key values?" 和Dolph's answer 覆盖。

【讨论】:

【参考方案7】:

你可以像这样选择ID:

set @rank = 0;
select id, @rank:=@rank+1 from tbl order by id

结果是一个 id 列表,以及它们在序列中的位置。

您也可以像这样重置 id:

set @rank = 0;
update tbl a join (select id, @rank:=@rank+1 as rank from tbl order by id) b
  on a.id = b.id set a.id = b.rank;

你也可以像这样打印出第一个未使用的 id:

select min(id) as next_id from ((select a.id from (select 1 as id) a
  left join tbl b on a.id = b.id where b.id is null) union
  (select min(a.id) + 1 as id from tbl a left join tbl b on a.id+1 = b.id
  where b.id is null)) c;

每次插入后,您可以重置 auto_increment:

alter table tbl auto_increment = 16

或在插入时显式设置id值:

insert into tbl values (16, 'something');

通常这不是必需的,您拥有count(*) 并能够在结果集中创建排名数字。典型的排名可能是:

set @rank = 0;
select a.name, a.amount, b.rank from cust a,
  (select amount, @rank:=@rank+1 as rank from cust order by amount desc) b
  where a.amount = b.amount

客户按消费金额排名。

【讨论】:

【参考方案8】:

我可以想到很多您可能需要这样做的场景,尤其是在迁移或开发过程中。例如,我刚才必须通过交叉连接两个现有表来创建一个新表(作为复杂设置过程的一部分),然后我需要在事件之后添加一个主键。您可以删除现有的主键列,然后执行此操作。

ALTER TABLE my_table ADD `ID` INT NOT NULL AUTO_INCREMENT FIRST, ADD PRIMARY KEY (`ID`);

对于实时系统,这不是一个好主意,尤其是如果有其他表具有指向它的外键。

【讨论】:

【参考方案9】:

我有一个非常简单但很棘手的方法。

删除行时,您可以将 ID 保存到另一个临时表中。之后,当您将新数据插入主表时,您可以从临时表中搜索并选择 ID。所以在这里使用检查。如果临时表没有 ID,则计算最大 ID 到主表中,并将新 ID 设置为:new_ID = old_max_ID+1

注意:这里不能使用自动增量功能。

【讨论】:

【参考方案10】:

您正在尝试做的事情非常危险。仔细考虑一下。自动增量的默认行为有一个很好的理由。

考虑一下:

删除一个表中与另一个表有关系的记录。由于审计原因,不能删除第二张表中对应的记录。该记录成为第一个表的孤立记录。如果将新记录插入到第一个表中,并且使用顺序主键,则该记录现在链接到孤立记录。显然,这很糟糕。通过使用自动递增的 PK,始终可以保证以前从未使用过的 id。这意味着孤儿仍然是孤儿,这是正确的。

【讨论】:

【参考方案11】:

实际上有一种方法可以解决这个问题。首先删除 auto_incremented 主键列,然后再次添加,如下所示:

ALTER TABLE table_name DROP column_name;
ALTER TABLE table_name ADD column_name int not null auto_increment primary key first;

【讨论】:

【参考方案12】:

您可能会考虑在删除后创建一个触发器,这样您就可以更新 autoincrement 的值以及所有看起来不像您想要看到的行的 ID 值。

因此,您可以使用同一个表,并且每当您删除一行时,触发器会自动修复自动增量。

【讨论】:

link【参考方案13】:

您可以使用您的 mysql 客户端软件/脚本来指定删除所需记录后主键应从何处开始。

【讨论】:

【参考方案14】:

绝对不推荐。如果您有一个包含多个表的大型数据库,您可能已经在表 2 中保存了一个用户 ID 作为 id。如果您重新排列表 1,那么预期的用户 ID 可能最终不会成为预期的表 2 id。

【讨论】:

【参考方案15】:

MYSQL 查询 自动增量解决方案。当您在软件测试阶段插入许多记录时,它可以完美运行。现在您想向您的客户端实时启动您的应用程序,并且您想从 1 开始自动递增。

为了避免任何不必要的问题,为了更安全的一面 先导出.sql文件。 然后按照以下步骤操作:

步骤 1) 首先创建现有表的副本 MySQL 命令创建副本:

CREATE TABLE new_Table_Name  SELECT * FROM existing_Table_Name;

创建表的精确副本,其中包含除约束之外的所有行。 它不会将 Auto Increment 和 Primary Key 等约束复制到 new_Table_name

步骤 2) 删除所有行如果在测试阶段没有插入数据并且它没有用。 如果数据很重要,则直接进入步骤 3。

DELETE from new_Table_Name;

第 3 步)添加约束,转到表结构

3A) 从更多选项添加主键约束(如果需要)。 3B) 从更改选项添加自动增量约束。对于这个集合,定义值为None。 3C) 删除 existing_Table_Name 和 3D) 将 new_Table_Name 重命名为 existing_Table_Name。

现在它将完美运行。新的第一条记录将采用 Auto Increment 列中的第一个值。

【讨论】:

【参考方案16】:

这是解决问题的步骤。

在您的 .php 文件中,只需添加以下给出的查询:

<?php
$servername = "localhost";
$username = "root";
$password = "";
$dbname = "";

$conn = new mysqli($servername, $username, $password, $dbname);

if ($conn->connect_error) 
      die("Connection failed: " . $conn->connect_error);


//write the number or id you want to start with the next user in AUTO_INCREMENT    
$sql = "ALTER TABLE `table_name` AUTO_INCREMENT = number";
$conn->query($sql);
?> 

希望你的问题能得到解决。

【讨论】:

【参考方案17】:
if($id == 1) // deleting first row
            mysqli_query($db,"UPDATE employees  SET id=id-1 WHERE id>1");
        
        else if($id>1 && $id<$num) // deleting middle row
            mysqli_query($db,"UPDATE employees  SET id=id-1 WHERE id>$id");
        
        else if($id == $num) // deleting last row
            mysqli_query($db,"ALTER TABLE employees AUTO_INCREMENT = $num");
        
        else
            echo "ERROR";
        

        mysqli_query($db,"ALTER TABLE employees AUTO_INCREMENT = $num");

【讨论】:

MySQL 是一个关系型数据库。当有多个表时,需要在表之间定义关系。这是使用 ID 列完成的。这种方法的问题在于,如果您开始重新编号表的索引,则会对与其有关系的所有表产生连锁反应。【参考方案18】:

这里有一个功能可以解决您的问题

    public static void fixID(Connection conn, String table) 

    try 
        Statement myStmt = conn.createStatement();
        ResultSet myRs;
        int i = 1, id = 1, n = 0;
        boolean b;
        String sql;

        myRs = myStmt.executeQuery("select max(id) from " + table);
        if (myRs.next()) 
            n = myRs.getInt(1);
        
        while (i <= n) 
            b = false;
            myRs = null;
            while (!b) 
                myRs = myStmt.executeQuery("select id from " + table + " where id=" + id);
                if (!myRs.next()) 
                    id++;
                 else 
                    b = true;
                
            

            sql = "UPDATE " + table + " set id =" + i + " WHERE id=" + id;
            myStmt.execute(sql);
            i++;
            id++;
        

     catch (SQLException e) 
        e.printStackTrace();
    

【讨论】:

以上是关于MySQL中删除后自动增量的主要内容,如果未能解决你的问题,请参考以下文章

dbwritetable 删除 mysql 中的自动增量字段

修复自动增量mysql [重复]

如何在 SQL 数据库中删除行后修复自动增量不连续?

MySQL 和自动增量一致性

重新排序/重置自动增量主键

AUTOINCREMENT 自动增量