自動インクリメント主キーの並べ替え/リセット


127

自動インクリメントの主キーを持つMySQLテーブルがあります。テーブルの中央にあるいくつかの行を削除しました。たとえば、ID列に次のようなものがあります。12、13、14、19、20。15、16、17、18行を削除しました。

主キーの再割り当て/リセット/並べ替えを行い、継続性を確保します。つまり、19 a 15、20 a 16などにします。

どうすればできますか?

回答:


95

主キー列を削除して再作成できます。次に、すべてのIDを順番に再割り当てする必要があります。

ただし、これはほとんどの状況でおそらく悪い考えです。このテーブルへの外部キーを持つ他のテーブルがある場合、それは間違いなく機能しません。


このテーブルへの外部キーを保持する他のテーブルがありますが、プロジェクトを開始したばかりなので問題ありません。ありがとうございます。
ジョナサン

65
IDが常に連続しているわけではないことを受け入れ始めようとすると、長期的には最善かもしれません。
Ciaran McNulty

8
ALTER TABLE your_table AUTO_INCREMENT = 1
Sinac

356

この質問はかなり古いようですが、ここで検索を行った人に回答を投稿します。

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ます。


外部キーを使用したこれは、大量のジャンクが挿入および削除され、インデックススペースを節約したいという私のテーブルにとって非常に優れたソリューションです。
mukunda 2014

1
mySQL Docはこれに対して助言します:「SETステートメント以外の原則として、ユーザー変数に値を割り当てて、同じステートメント内で値を読み取ってはなりません。たとえば、変数をインクリメントする場合、これは問題ありません:SET @a = @a + 1; SELECTなどの他のステートメントでは、期待どおりの結果が得られる可能性がありますが、これは保証されません。次のステートメントでは、MySQLが最初に@aを評価してから割り当てを行うと考えるかもしれません2番目:SELECT @a、@a:= @ a + 1、...;ただし、ユーザー変数を含む式の評価の順序は定義されていません。 "
ReverseEMF

3
@ReverseEMF:いいえ。割り当ての順序はMySQL式で固定されています。あなたが引用したものから、MySQLドキュメントは変数の複数の独立した使用に対してアドバイスをします。上記の場合、単一の割り当て式 `` users .id` = @count:= @count + 1`のため、式の評価は事前定義された順序で発生するようにバインドされています。ドキュメントから:「右側の値は、リテラル値、値を格納する別の変数、またはスカラー値を生成する任意の正当な式である可能性があります」
Anshul

1
これは非常に高額な発言ですか?マルチギガバイトのテーブルではどのように機能しますか?ibdata1(長いトランザクション)を爆破し、テーブルを長時間ブロックしているのではないかと心配です。
ステファン

1
@Stefan + 2GBのデータで別のキーを参照する外部キーを持つテーブル(5MB)で、このスクリプトは5分以上かかりませんでした。システムにはSSDがあるので、かなり役に立ったと思います。fkにはON UPDATE CASCADE
fernandezrが

60

ユーザーテーブルの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;

584k行のMyISAMテーブルでは、約7.3秒かかりました。
user1278519

3
私が100票を獲得した場合、理解に役立つ私のようなnoobのsqlステートメントを分解するので、私は常にこれに賛成票を投じたでしょう
repzero

1
2行目は不要ですか、それとも間違っていますか?それ自体は1で始まりますが、InnoDBの場合は、私にとってはそうでした
Thielicious

2行目は不要です。
KawaiKx 2017年

1
@JorgeAugustoMorêradeMouraレコードの順序は変更されません
Ryan

31

あなたは単にこのクエリを使用することができます

alter table abc auto_increment = 1;

2
この場合、これは機能しません。ISAMテーブルの場合、autoinc値をmax(id)+ 1に設定します。InnoDBの場合は何もしません。AUTOINCREMENT dev.mysql.com/doc/refman/5.0/en/alter-table.htmlの
lreeder

3
@Ireederの5.6以降のinnodbの動作は、myisamの動作と同様です
Anshul

このテーブルへの外部キーを持つ他のテーブルがある場合、これはそれらを壊しますか?
カイルヴァセッラ

15
SET  @num := 0;

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

ALTER TABLE your_table AUTO_INCREMENT =1;

これでうまくいくと思います


12

または、PhpMyAdminから、「AutoIncrement」フラグを削除して保存し、再度設定して、saveを実行すると、リセットされます。


現在のphpmyadminバージョンではテストできません。私の答えはかなり古いです...私に反対票を投じた場合、それを修正していただけますか
lbrutti

3
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


1

phpmyadmin

注:これは、中央の行ではなく最後の行を削除した場合に機能します。

テーブルに移動->オペレーションメニューをクリック->テーブルオプションに移動-> AUTO_INCREMENTを、開始したい場所から変更します。

テーブルの自動インクリメントはその番号から始まります。

それを試してみてください。 ここに画像の説明を入力してください


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

0

InnoDBの場合、これを実行します(これにより、テーブルからすべてのレコードが削除され、最初にベイクカップが作成されます)。

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 ;

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;

解決策はかかりますが、安全であり、私のテーブルが別のテーブルのデータを含む外部キーを所有していたために必要でした。


0

最良の選択は、列を変更してauto_increment属性を削除することです。次に、別のalterステートメントを発行して、auto_incrementを列に戻します。これにより、カウントが現在の行のmax + 1にリセットされ、データベース内の他のテーブルからこのテーブルへの外部キー参照、またはその列の他のキー使用法が保持されます。


0

私の意見では、row_orderという新しい列を作成します。次に、その列を並べ替えます。主キーの変更を受け入れません。例として、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)));
        }
    }
}

0

これは機能します -https://stackoverflow.com/a/5437720/10219008 ...以下。更新クエリに無視を追加します。

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

-2

また、数値IDを主キーとして使用しないようにすることもできます。テーブルに国の情報が含まれている場合は、国コードをプライマリIDとして使用できます。たとえば、記事が含まれている場合は、パーマリンクを使用できます。

単にランダムな値またはMD5値を使用することもできます。このすべてのオプションには、それ自体の利点があり、特にIT部門に利点があります。数値IDは簡単に列挙できます。


1
...これは何に基づいていますか?たぶん、 "complete_user_info_export.php?userid = 34"のようなページを作成しないでください。内部的に文字列またはその他のランダムな値をインデックス/識別子として使用することは、非常に悪い考えです。解決するよりも多くの問題を作成します(問題を解決する場合でも)
Rob

2つの異なる値またはデータセットが同じMD5値を生成する可能性があるため、MD5値は絶対的に最悪の可能性です。だから私はそれを解決策とは呼びません。
David
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.