Susun ulang / reset kunci primer kenaikan otomatis

127

Saya memiliki tabel MySQL dengan kunci primer kenaikan otomatis. Saya menghapus beberapa baris di tengah meja. Sekarang saya memiliki, misalnya, sesuatu seperti ini di kolom ID: 12, 13, 14, 19, 20. Saya menghapus 15, 16, 17 dan 18 baris.

Saya ingin menetapkan ulang / mengatur ulang / menyusun ulang kunci utama sehingga saya memiliki kontinuitas, yaitu membuat 19 menjadi 15, 20 menjadi 16, dan seterusnya.

Bagaimana saya bisa melakukannya?

Jonathan
sumber

Jawaban:

95

Anda bisa menjatuhkan kolom kunci utama dan membuatnya kembali. Semua id harus kemudian dipindahkan secara berurutan.

Namun ini mungkin ide yang buruk di sebagian besar situasi. Jika Anda memiliki tabel lain yang memiliki kunci asing ke tabel ini maka pasti tidak akan berfungsi.

Tom Haigh
sumber
Saya punya tabel lain yang memegang kunci asing ke tabel ini, tapi saya baru memulai proyek jadi tidak masalah untuk saya .. Terima kasih!
Jonathan
65
Mungkin jangka panjang terbaik jika Anda mencoba dan mulai menerima bahwa ID Anda tidak akan selalu berurutan, jika tidak ketika Anda mulai bekerja pada proyek yang lebih besar itu akan benar-benar gila!
Ciaran McNulty
8
ALTER TABLE your_table AUTO_INCREMENT = 1
Sinac
356

Meskipun pertanyaan ini tampaknya sudah sangat lama, akan memposting jawaban untuk seseorang yang mencari di sini.

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

Jika kolom digunakan sebagai kunci asing di tabel lain, pastikan Anda menggunakan ON UPDATE CASCADEalih-alih defaultON UPDATE NO ACTION untuk hubungan kunci asing di tabel tersebut.

Selanjutnya, untuk mengatur ulang AUTO_INCREMENThitungan, Anda dapat segera mengeluarkan pernyataan berikut.

ALTER TABLE `users` AUTO_INCREMENT = 1;

Untuk MySQL, nilai itu akan disetel ulang menjadi MAX(id) + 1.

Anshul
sumber
Ini dengan kunci asing adalah solusi yang sangat keren untuk meja saya di mana banyak sampah dimasukkan dan dihapus dan saya ingin menghemat ruang indeks.
mukunda
1
mySQL Doc menyarankan ini: "Sebagai aturan umum, selain dalam pernyataan SET, Anda tidak boleh menetapkan nilai untuk variabel pengguna dan membaca nilai dalam pernyataan yang sama. Misalnya, untuk menambah variabel, ini boleh saja: SET @a = @a +1; Untuk pernyataan lain, seperti SELECT, Anda mungkin mendapatkan hasil yang Anda harapkan, tetapi ini tidak dijamin. Dalam pernyataan berikut, Anda mungkin berpikir bahwa MySQL akan mengevaluasi @a terlebih dahulu dan kemudian melakukan penugasan kedua: SELECT @a, @a: = @ a +1, ...; Namun, urutan evaluasi untuk ekspresi yang melibatkan variabel pengguna tidak terdefinisi. "
ReverseEMF
3
@ReverseEMF: Tidak. Urutan penugasan diperbaiki dalam ekspresi MySQL. Dari apa yang Anda kutip, dokumentasi MySQL menyarankan agar beberapa variabel tidak digunakan secara independen. Dalam kasus di atas, evaluasi ekspresi pasti terjadi dalam urutan yang telah ditentukan karena ekspresi penugasan tunggal `` users .id` = @count: = @count + 1`. Dari dokumentasi: "Nilai di sisi kanan mungkin nilai literal, variabel lain yang menyimpan nilai, atau ekspresi hukum apa pun yang menghasilkan nilai skalar"
Anshul
1
Apakah ini pernyataan yang sangat mahal? Bagaimana kinerjanya dalam tabel multi gigabyte? Saya takut meledakkan ibdata1 saya (transaksi lama) dan memblokir meja terlalu lama.
Stefan
1
@Stefan Di atas meja (5MB) dengan kunci asing yang merujuk orang lain dengan data + 2GB, skrip ini tidak membutuhkan waktu lebih dari lima menit. Sistem memiliki ssd, jadi saya kira itu banyak membantu. Fk memiliki ON UPDATE CASCADE
fernandezr
60

Untuk mengatur ulang ID tabel Pengguna saya, saya menggunakan query SQL berikut. Dikatakan di atas bahwa ini akan merusak hubungan yang mungkin Anda miliki dengan tabel lain.

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;
Ryan
sumber
Di meja MyISAM dengan baris 584k, butuh sekitar 7,3 detik.
user1278519
3
Jika saya memiliki 100 suara saya akan memilih ini sepanjang waktu karena itu memecah pernyataan sql untuk noob seperti saya yang membantu dalam memahami
repzero
1
Baris kedua tidak perlu atau saya salah? Itu dimulai dengan 1 sendiri ,,,, untuk InnoDB itu untuk saya
Thielicious
baris kedua tidak perlu.
KawaiKx
1
@ JorgeAugustoMorêradeMoura urutan catatan tidak akan diubah
Ryan
31

Anda dapat menggunakan kueri ini

alter table abc auto_increment = 1;
Aaron W.
sumber
2
Ini tidak akan berfungsi dalam kasus ini. Untuk tabel ISAM, ini akan menetapkan nilai autoinc ke maks (id) + 1. Untuk InnoDB tidak akan melakukan apa-apa. Lihat mengubah dokumen tabel untuk mengubah AUTOINCREMENT dev.mysql.com/doc/refman/5.0/en/alter-table.html
lreeder
3
@Ireeder dari 5.6 dan seterusnya perilaku untuk innodb mirip dengan myisam
Anshul
Jika Anda memiliki tabel lain yang memiliki kunci asing ke tabel ini, apakah ini akan memecahnya?
Kyle Vassella
15
SET  @num := 0;

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

ALTER TABLE your_table AUTO_INCREMENT =1;

Saya pikir ini akan melakukannya

bagyei37
sumber
12

Atau, dari PhpMyAdmin, hapus bendera "AutoIncrement", simpan, atur lagi dan simpan. Ini akan mengatur ulang.

lbrutti
sumber
Maaf, saya tidak dapat menguji dengan versi phpmyadmin saat ini. Jawaban saya sudah cukup tua ... Jika Anda menurunkan saya, bisakah Anda mengubahnya?
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;

jika Anda menghendaki order by

Shubham Malik
sumber
1

dalam phpmyadmin

Catatan: ini akan berfungsi jika Anda menghapus baris terakhir bukan baris tengah.

goto meja Anda-> klik menu operasi-> opsi tabel goto-> ubah AUTO_INCREMENT menjadi tidak dari tempat Anda ingin memulai.

peningkatan otomatis tabel Anda dimulai dari no itu.

Cobalah. masukkan deskripsi gambar di sini

Anjani Barnwal
sumber
0

Anda bisa menghapus fungsi kenaikan otomatis kunci utama kolom itu, lalu setiap kali Anda memperbarui kolom itu jalankan kueri sebelumnya yang akan menghitung semua baris dalam tabel, lalu jalankan loop yang beralih melalui penghitungan baris yang memasukkan setiap nilai ke dalam baris masing-masing, dan akhirnya jalankan kueri yang menyisipkan baris baru dengan nilai kolom itu menjadi jumlah total baris ditambah satu. Ini akan bekerja dengan sempurna dan merupakan solusi paling absolut untuk seseorang yang berusaha mencapai apa Anda. Berikut adalah contoh kode yang dapat Anda gunakan untuk fungsi:

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

Di sini saya membuat array asosiatif yang telah saya tambahkan pada kolom peringkat dengan kueri dalam kueri pemilihan, yang memberi setiap baris nilai peringkat dimulai dengan 1. Saya kemudian mengulangi melalui array asosiatif.

Opsi lain adalah untuk mendapatkan jumlah baris, menjalankan kueri pemilihan dasar, mendapatkan array asosiatif dan mengulanginya melalui cara yang sama tetapi dengan variabel tambahan yang diperbarui melalui setiap iterasi. Ini kurang fleksibel tetapi akan mencapai hal yang sama.

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

untuk InnoDB, lakukan ini (ini akan menghapus semua catatan dari sebuah tabel, buat bakcup terlebih dahulu):

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 ;
Luis
sumber
0

Saya memiliki keraguan yang sama, tetapi tidak dapat membuat perubahan apa pun di atas meja, saya memutuskan melakukan yang berikut setelah melihat ID saya tidak melebihi jumlah maksimum yang tersimpan dalam variabel @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;

Solusi diperlukan, tetapi aman dan itu perlu karena meja saya memiliki kunci asing dengan data di tabel lain.

Rodrigo Prazim
sumber
0

Pilihan terbaik adalah mengubah kolom dan menghapus atribut auto_increment. Kemudian keluarkan pernyataan perubahan lain dan kembalikan auto_increment ke kolom. Ini akan mereset penghitungan ke maksimum +1 baris saat ini dan dengan demikian mempertahankan referensi kunci asing kembali ke tabel ini, dari tabel lain di database Anda, atau penggunaan kunci lain untuk kolom itu.

Grwww
sumber
0

Pendapat saya adalah membuat kolom baru bernama row_order. kemudian susun ulang kolom itu. Saya tidak menerima perubahan pada kunci utama. Sebagai contoh, jika kolom pesanan adalah banner_position, saya telah melakukan sesuatu seperti ini, Ini untuk menghapus, memperbarui, membuat kolom posisi banner. Panggil fungsi ini mengatur ulang mereka masing-masing.

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)));
        }
    }
}
Viraj Amarasinghe
sumber
0

Ini berfungsi - https://stackoverflow.com/a/5437720/10219008.....tapi jika Anda mengalami masalah 'Kode Kesalahan: 1265. Data terpotong untuk kolom' id 'di baris 1' ... Kemudian jalankan pengikut. Menambahkan abaikan pada permintaan pembaruan.

SET @count = 0;
set sql_mode = 'STRICT_ALL_TABLES';
UPDATE IGNORE web_keyword SET id = @count := (@count+1);
Anush BM
sumber
-2

Anda juga bisa menghindari menggunakan ID numerik sebagai Kunci Utama. Anda dapat menggunakan kode Negara sebagai id utama jika tabel berisi informasi negara, atau Anda dapat menggunakan permalinks, jika itu berisi artikel misalnya.

Anda juga bisa menggunakan nilai acak, atau MD5. Semua opsi ini memiliki manfaatnya sendiri, khususnya pada detik IT. ID numerik mudah dihitung.

Chris Russo
sumber
1
... Kamu mendasarkan apa ini? Mungkin hanya tidak membuat halaman seperti "complete_user_info_export.php? Userid = 34"? Secara internal menggunakan string atau nilai acak lainnya sebagai indeks / pengenal adalah ide yang sangat buruk. Ini menciptakan lebih banyak masalah daripada memecahkan (jika bahkan memecahkan masalah)
Rob
Nilai MD5 adalah kemungkinan terburuk mutlak karena kemungkinan bahwa dua nilai atau kumpulan data yang berbeda menghasilkan nilai MD5 yang sama. Jadi saya tidak akan menyebutnya solusi.
David