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

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

我想重新分配/重新设置/重新排序主键,这样我就有了连续性,比如把19变成15,把20变成16,等等。

我该怎么做?

247558 次浏览

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

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

您可以简单地使用这个查询

alter table abc auto_increment = 1;

要重置 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;

尽管这个问题看起来很古老,但是会为那些在这里搜索的人提供一个答案。

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

或者,从 PhpMyAdmin 中,删除“自动增量”标志,保存,再次设置它,然后保存。

SET  @num := 0;


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


ALTER TABLE your_table AUTO_INCREMENT =1;

我觉得这个可以

您可以删除该列的主键自动递增功能,然后每次更新该列之前运行一个查询,该查询将计算表中所有行的数量,然后运行一个循环,循环遍历该行计数,将每个值插入相应的行,最后运行一个查询,插入一个新行,该列的值为总行计数加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')");

在这里,我创建了一个关联数组,我将它附加在一个 rank 列上,并在 select 查询中使用查询,它给每一行一个从1开始的 rank 值。然后我重复了一遍关联数组。

另一种选择是获取行数,运行一个基本的 select 查询,获取关联数组,然后通过相同的方式迭代它,但是添加一个变量,在每次迭代中更新。这种方法的灵活性较差,但能达到同样的效果。

$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')");

对于 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 ;

您还可以简单地避免使用数字 ID 作为主键。如果表中包含国家信息,则可以使用 Country 代码作为主 id; 如果表中包含文章,则可以使用 permalinks。

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

我有同样的疑问,但不能做任何改变,我决定做以下事情,看到我的 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;

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

最好的选择是更改列并删除 auto _  增量特性。然后发出另一个 alter 语句,并将 auto _ Increment 放回到列上。这将把计数重置为当前行的最大 + 1,从而保留对该表、数据库中其他表或该列的任何其他键使用的外键引用。

在 phpmyadmin

注意: 如果删除的是最后一行,而不是中间的行,那么这个命令就会起作用。

转到你的表-> 点击操作菜单-> 转到表选项-> 将 AUTO _ INCREMENT 从你想要开始的地方改为 no。

你的表自动递增从那个否开始。

试试看。 enter image description here

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

我的观点是创建一个名为 row _ order 的新列。然后重新排列那一列。我不接受对主键的更改。作为一个例子,如果订单列的旗帜 _ 位置,我已经做了这样的事情,这是为删除,更新,创建旗帜位置列。分别调用这个函数对它们进行重新排序。

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)));
}
}
}

如果遇到问题“错误代码: 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);

删除 id column并执行 ALTER TABLE table_name ADD COLUMN id INT NOT NULL AUTO_INCREMENT UNIQUE;