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

时间:2009-04-11 16:11:39

标签: mysql database

我有一个带有自动增量主键的MySQL表。我删除了表中间的一些行。现在我在ID列中有这样的东西:12,13,14,19,20。我删除了15,16,17和18行。

我想重新分配/重置/重新排序主键,以便我有连续性,即使19 a 15,20 a 16,依此类推。

我该怎么做?

15 个答案:

答案 0 :(得分:327)

即使这个问题看起来很旧,也会为在这里搜索的人发布答案。

SET @count = 0;
UPDATE `users` SET `users`.`id` = @count:= @count + 1;

如果该列在其他表中用作外键,请确保在这些表中使用ON UPDATE CASCADE而不是默认ON UPDATE NO ACTION作为外键关系。

此外,为了重置AUTO_INCREMENT计数,您可以立即发出以下声明。

ALTER TABLE `users` AUTO_INCREMENT = 1;

对于MySQL,它会将值重置为MAX(id) + 1

答案 1 :(得分:85)

您可以删除主键列并重新创建它。然后应按顺序重新分配所有ID。

然而,在大多数情况下,这可能是一个坏主意。如果你有其他表有这个表的外键,那么它肯定不会工作。

答案 2 :(得分:52)

要重置我的User表的ID,我使用以下SQL查询。上面已经说过,这将破坏你与任何其他表格之间的任何关系。

ALTER TABLE `users` DROP `id`;
ALTER TABLE `users` AUTO_INCREMENT = 1;
ALTER TABLE `users` ADD `id` int UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY FIRST;

答案 3 :(得分:29)

您可以简单地使用此查询

alter table abc auto_increment = 1;

答案 4 :(得分:14)

SET  @num := 0;

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

ALTER TABLE your_table AUTO_INCREMENT =1;

我认为这样做会

答案 5 :(得分:13)

或者,从PhpMyAdmin中删除“AutoIncrement”标志,保存,再次设置并保存。这会重置它。

答案 6 :(得分:1)

在phpmyadmin中

  

注意:如果删除最后一行而不是中间行,这将有效。

转到你的表格 - >点击操作菜单 - > goto table options->将AUTO_INCREMENT改为你想要开始的地方。

你的表格自动增量从那个号码开始。

试试吧。 enter image description here

答案 7 :(得分:1)

SELECT * from `user` ORDER BY `user_id`; 

SET @count = 0;

UPDATE `user`  SET `user_id` = @count:= @count + 1;

ALTER TABLE `user_id` AUTO_INCREMENT = 1;

如果您想order by

答案 8 :(得分:0)

您可以删除该列的主键自动增量功能,然后每次更新该列时,先运行查询,然后计算表中的所有行,然后运行循环,遍历插入每个行的行数将值放入相应的行,最后运行插入新行的查询,该行的值为总行数加1。这将完美无瑕地工作,是尝试完成你的人的最绝对的解决方案。以下是您可以用于该功能的代码示例:

$table_row_count = mysql_result(mysql_query("SELECT COUNT(`field_1`) FROM `table`"), 0);
$viewsrowsdata = mysql_query("
    SELECT `rank`, `field1`, `field2`, `field3`, `field4`
        FROM (SELECT (@rank:=@rank+1) as `rank`, `field1`, `field2`, `field3`, `field4`
            FROM (SELECT * FROM `views`) a
            CROSS JOIN (SELECT @rank:=0) b
            ORDER BY rank ASC) c
");
while ($row = mysql_fetch_assoc($viewsrowsdata)) {
    $data[] = $row;
}
foreach ($data as $row) {
    $new_field_1 = (int)$row['rank'];
    $old_field_1 = (int)$row['field1'];
    mysql_query("UPDATE `table` SET `field_1` = $new_field_1 WHERE `field_1` = $old_field_1");
}
mysql_query("INSERT INTO `table` (`field1`, `field2`, `field3`, `field4`) VALUES ('$table_row_count' + 1, '$field_2_value', 'field_3_value', 'field_4_value')");

在这里,我创建了一个关联数组,我在一个排名列上附加了一个select查询中的查询,它为每一行提供了一个以1开头的排名值。然后迭代通过关联数组。

另一种选择是获取行计数,运行基本选择查询,获取关联数组并通过相同的方式迭代它,但添加的变量通过每次迭代更新。这不太灵活,但会完成同样的事情。

$table_row_count = mysql_result(mysql_query("SELECT COUNT(`field_1`) FROM `table`"), 0);
$viewsrowsdata = mysql_query("SELECT * FROM `table`");
$updated_key = 0;
while ($row = mysql_fetch_assoc($viewsrowsdata)) {
    $data[] = $row;
}
foreach ($data as $row) {
    $updated_key = $updated_key + 1;
    mysql_query("UPDATE `table` SET `field_1` = '$updated_key' WHERE `field_1` = '$row['field_1']'");
}
mysql_query("INSERT INTO `table` (`field1`, `field2`, `field3`, `field4`) VALUES ('$table_row_count' + 1, '$field_2_value', 'field_3_value', 'field_4_value')");

答案 9 :(得分:0)

对于InnoDB,执行此操作(这将删除表中的所有记录,首先进行bakcup):

SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS ;
SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION ;
SET NAMES utf8 ;
SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 ;
SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 ;
SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' ;
SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 ;
/* ================================================= */

drop table tablename;
CREATE TABLE `tablename` (
   table structure here!

) ENGINE=InnoDB AUTO_INCREMENT=  ai number to reset  DEFAULT CHARSET= char set here;



/* ================================================= */
SET SQL_MODE=@OLD_SQL_MODE ;
SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS ;
SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS ;
SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT ;
SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS ;
SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION ;
SET SQL_NOTES=@OLD_SQL_NOTES ;

答案 10 :(得分:0)

我有同样的疑虑,但无法对表格进行任何更改,我决定在看到我的ID未超过变量@count中设置的最大数量时执行以下操作:

SET @count = 40000000;
UPDATE `users` SET `users`.`id` = @count:= @count + 1;

SET @count = 0;
UPDATE `users` SET `users`.`id` = @count:= @count + 1;

ALTER TABLE `users` AUTO_INCREMENT = 1;

解决方案需要,但它是安全的,并且它是必要的,因为我的表拥有另一个表中的数据的外键。

答案 11 :(得分:0)

最好的选择是更改列并删除auto_increment属性。然后发出另一个alter语句并将auto_increment放回到列中。这会将计数重置为当前行的最大值+ 1,从而将外键引用保留回此表,数据库中的其他表或该列的任何其他密钥用法。

答案 12 :(得分:0)

我的意见是创建一个名为row_order的新列。然后重新排序该列。我不接受主键的更改。例如,如果订单列是banner_position,我已经做了类似的事情,这是为了删除,更新,创建标题位置列。调用此函数分别对其重新排序。

public function updatePositions(){
    $offers = Offer::select('banner_position')->orderBy('banner_position')->get();
    $offersCount = Offer::max('banner_position');
    $range = range(1, $offersCount);

    $existingBannerPositions = [];
    foreach($offers as $offer){
        $existingBannerPositions[] = $offer->banner_position;
    }
    sort($existingBannerPositions);
    foreach($existingBannerPositions as $key => $position){
        $numbersLessThanPosition = range(1,$position);
        $freshNumbersLessThanPosition = array_diff($numbersLessThanPosition, $existingBannerPositions);
        if(count($freshNumbersLessThanPosition)>0) {
            $existingBannerPositions[$key] = current($freshNumbersLessThanPosition);
            Offer::where('banner_position',$position)->update(array('banner_position'=> current($freshNumbersLessThanPosition)));
        }
    }
}

答案 13 :(得分:0)

这有效-如果遇到问题“错误代码:1265,https://stackoverflow.com/a/5437720/10219008.....but。第1行的列'id'的数据被截断了...”,然后运行以下命令。在更新查询上添加忽略。

SET @count = 0;
set sql_mode = 'STRICT_ALL_TABLES';
UPDATE IGNORE web_keyword SET id = @count := (@count+1);

答案 14 :(得分:-2)

您也可以简单地避免使用数字ID作为主键。如果表格包含国家/地区信息,您可以使用国家/地区代码作为主要ID,或者如果它包含文章,您可以使用永久链接。

您也可以简单地使用随机或MD5值。所有这些选项都有它自己的好处,特别是在IT秒。数字ID很容易枚举。