Otomatik artış birincil anahtarını yeniden sıralama / sıfırlama


127

Otomatik artan birincil anahtarı olan bir MySQL tablom var. Tablonun ortasındaki bazı satırları sildim. Şimdi, örneğin, Kimlik sütununda şöyle bir şey var: 12, 13, 14, 19, 20. 15, 16, 17 ve 18 satırları sildim.

Sürekliliğe sahip olmak için birincil anahtarı yeniden atamak / sıfırlamak / yeniden sıralamak istiyorum, yani 19'u 15, 20'yi 16 vb. Yapmak.

Nasıl yapabilirim?

Yanıtlar:


95

Birincil anahtar sütununu bırakıp yeniden oluşturabilirsiniz. Tüm kimlikler daha sonra sırayla yeniden atanmalıdır.

Ancak bu, çoğu durumda muhtemelen kötü bir fikirdir. Bu tablonun yabancı anahtarları olan başka tablolarınız varsa kesinlikle çalışmayacaktır.


Bu masaya yabancı anahtar tutan başka masalarım var, ancak projeye yeni başlıyorum, bu yüzden benim için sorun yok .. Teşekkürler!
Jonathan

65
Kimliklerinizin her zaman sıralı olmayacağını kabul etmeye çalışırsanız en iyisi uzun vadeli olabilir, aksi takdirde daha büyük projeler üzerinde çalışmaya başladığınızda gerçekten delirecek!
Ciaran McNulty.

8
ALTER TABLE your_table AUTO_INCREMENT = 1
Sinac

356

Bu soru oldukça eski gibi görünse de, buraya arayarak ulaşan biri için bir cevap verecektir.

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

Sütun diğer tablolarda yabancı anahtar olarak kullanılıyorsa , bu tablolarda yabancı anahtar ilişkisi için ON UPDATE CASCADEvarsayılan yerine kullandığınızdan emin olun ON UPDATE NO ACTION.

Ayrıca AUTO_INCREMENTsayımı sıfırlamak için aşağıdaki ifadeyi hemen verebilirsiniz.

ALTER TABLE `users` AUTO_INCREMENT = 1;

MySQL'ler için değeri olarak sıfırlayacaktır MAX(id) + 1.


Yabancı anahtarlarla bu, çok sayıda gereksiz yere yerleştirilip silindiği ve dizin alanından tasarruf etmek istediğim masam için çok harika bir çözüm.
mukunda

1
mySQL Doc buna karşı tavsiyede bulunur: "Genel bir kural olarak, SET ifadeleri dışında, bir kullanıcı değişkenine hiçbir zaman bir değer atamamalı ve aynı ifade içindeki değeri okumamalısınız. Örneğin, bir değişkeni artırmak için sorun değil: SET @a = @a + 1; SELECT gibi diğer ifadeler için beklediğiniz sonuçları alabilirsiniz, ancak bu garanti edilmez.Aşağıdaki ifadede, MySQL'in önce @a'yı değerlendireceğini ve sonra bir atama yapacağını düşünebilirsiniz saniye: SELECT @a, @a: = @ a + 1, ...; Ancak, kullanıcı değişkenlerini içeren ifadelerin değerlendirme sırası tanımsız. "
TersEMF

3
@ReverseEMF: Hayır. MySQL ifadelerinde atama sırası sabittir. Alıntı yaptığınızdan, MySQL dokümantasyonu değişkenin birden çok bağımsız kullanımına karşı tavsiyede bulunur. Yukarıdaki durumda, "users .id" = @count: = @count + 1 "tek bir atama ifadesi nedeniyle ifadenin değerlendirilmesi önceden tanımlanmış bir sırayla gerçekleşmek zorundadır. Belgelerden: "Sağ taraftaki değer, gerçek bir değer, bir değeri depolayan başka bir değişken veya skaler bir değer veren herhangi bir yasal ifade olabilir"
Anshul

1
Bu çok pahalı bir ifade mi? Çoklu gigabaytlık bir tabloda nasıl performans gösterir? İbdata1'imi (uzun işlem) havaya uçurmaktan ve masayı çok uzun süre bloke etmekten korkuyorum.
Stefan

1
@Stefan + 2GB veriye sahip başka birine başvuran yabancı anahtarlara sahip bir tabloda (5MB), bu komut dosyası beş dakikadan fazla sürmedi. Sistemin bir SSD'si var, bu yüzden çok yardımcı olduğunu düşünüyorum. FK ON GÜNCELLEME KADEMESİNİ YAPTI
Fernandezr

60

Kullanıcı tablomun kimliklerini sıfırlamak için aşağıdaki SQL sorgusunu kullanıyorum. Yukarıda, bunun diğer tablolarla sahip olabileceğiniz tüm ilişkileri mahvedeceği söylendi.

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 sıralı bir MyISAM tablosunda yaklaşık 7,3 saniye sürdü.
user1278519

3
Ben 100 oy olsaydı yardım anlamada benim gibi bir noob için sql ifadeleri ayırır beri Hep bu kadar oy vereceklerdi
oyum olsaydı oylardım repzero

1
İkinci satır gerekli değil mi yoksa yanılıyor muyum? Kendi başına 1 ile başlıyor ,,,, InnoDB için benim için de yaptı
Thielicious

ikinci satır gerekli değil.
KawaiKx

1
@ JorgeAugustoMorêradeMoura kayıtların sırası değiştirilmeyecek
Ryan

31

Sadece bu sorguyu kullanabilirsiniz

alter table abc auto_increment = 1;

2
Bu, bu durumda işe yaramaz. ISAM tabloları için, autoinc değerini max (id) + 1 olarak ayarlayacaktır. InnoDB için hiçbir şey yapmayacaktır. AUTOINCREMENT dev.mysql.com/doc/refman/5.0/en/alter-table.html
lreeder

3
@ Innodb için 5.6'dan sonraki davranış, myisam'ınkine benzer
Anshul

Bu tablonun yabancı anahtarları olan başka tablolarınız varsa, bu onları bozar mı?
Kyle Vassella

15
SET  @num := 0;

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

ALTER TABLE your_table AUTO_INCREMENT =1;

Bence bunu yapacak


12

Veya PhpMyAdmin'den "AutoIncrement" bayrağını kaldırın, kaydedin, yeniden ayarlayın ve kaydedin. Bu onu sıfırlar.


Üzgünüm, mevcut phpmyadmin sürümleriyle test edemiyorum. Cevabım oldukça eski ... Bana olumsuz oy verdiyseniz, lütfen düzeltebilir misiniz?
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;

Eğer istersen order by


1

phpmyadmin'de

not: bu, ortadaki satırları değil son satırları silerseniz çalışacaktır.

tablonuza gidin-> işlemler menüsüne tıklayın-> tablo seçeneklerine git-> AUTO_INCREMENT'i başlamak istediğiniz yerden hayır olarak değiştirin.

Tablonuzun otomatik artışı bu hayırdan başlar.

dene. görüntü açıklamasını buraya girin


0

Bu sütunun birincil anahtar otomatik artırma işlevini kaldırabilir, ardından bu sütunu her güncellediğinizde, elden önce tablodaki tüm satırları sayacak bir sorgu çalıştırabilir, ardından bu satır sayımını yineleyen bir döngü çalıştırarak her bir değeri ilgili satır ve son olarak, o sütunun değeri toplam satır sayısı artı bir olan yeni bir satır ekleyen bir sorgu çalıştırın. Bu kusursuz bir şekilde çalışacak ve olduğunuz şeyi başarmaya çalışan biri için en mutlak çözüm olacaktır. İşte işlev için kullanabileceğiniz bir kod örneği:

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

Burada, bir seçme sorgusu içindeki sorguyla birlikte bir sıralama sütununa eklediğim, her satıra 1 ile başlayan bir sıra değeri veren bir ilişkilendirilebilir dizi oluşturdum. Daha sonra ilişkilendirilebilir dizi boyunca yineledim.

Diğer bir seçenek, satır sayısını elde etmek, temel bir seçme sorgusu çalıştırmak, ilişkilendirilebilir diziyi almak ve onu aynı şekilde yinelemek, ancak her yinelemede güncellenen ek bir değişkenle olurdu. Bu daha az esnektir ancak aynı şeyi başaracaktır.

$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 için şunu yapın (bu, bir tablodaki tüm kayıtları kaldıracak, önce bir bakcup oluşturacaktır):

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

Aynı şüphelerim vardı, ancak tabloda herhangi bir değişiklik yapamadım, kimliğimin @count değişkeninde ayarlanan maksimum sayıyı geçmediğini gördükten sonra aşağıdakileri yapmaya karar verdim:

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;

Çözüm alır, ancak güvenli ve gerekliydi çünkü tablomda başka bir tablodaki verilerle yabancı anahtarlar vardı.


0

En iyi seçenek, sütunu değiştirmek ve auto_increment özelliğini kaldırmaktır. Sonra başka bir alter ifadesi yayınlayın ve auto_increment öğesini sütuna geri koyun. Bu, sayımı geçerli satırların maksimum + 1'ine sıfırlar ve böylece bu tabloya, veritabanınızdaki diğer tablolardan veya o sütun için diğer anahtar kullanımlarından gelen yabancı anahtar referanslarını korur.


0

Benim fikrim, row_order adlı yeni bir sütun oluşturmaktır. daha sonra bu sütunu yeniden sıralayın. Birincil anahtardaki değişiklikleri kabul etmiyorum. Örnek olarak, sipariş sütunu banner_position ise, şöyle bir şey yaptım, Bu, banner konumu sütununu silmek, güncellemek, oluşturmak içindir. Bu işlevi çağırın sırasıyla onları yeniden sıralayın.

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

Bu çalışır - https ://stackoverflow.com/a/5437720/10219008..... ancak bir sorunla karşılaşırsanız 'Hata Kodu: 1265. Veriler satır 1'de' id 'sütunu için kesildi ... Sonra çalıştırın devamındaki. Güncelleme sorgusuna yok sayma ekleniyor.

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

-2

Ayrıca sayısal kimlikleri Birincil Anahtar olarak kullanmaktan da kaçınabilirsiniz. Tabloda ülke bilgileri bulunuyorsa Ülke kodlarını birincil kimlik olarak veya örneğin makaleler içeriyorsa kalıcı bağlantıları kullanabilirsiniz.

Ayrıca rastgele veya bir MD5 değeri de kullanabilirsiniz. Tüm bu seçeneklerin, özellikle BT alanında kendi avantajları vardır. sayısal kimliklerin numaralandırılması kolaydır.


1
... Bunu neye dayandırıyorsunuz? Belki "complete_user_info_export.php? Userid = 34" gibi sayfalar yapmazsınız? Dahili olarak dizin / tanımlayıcı olarak bir dizeyi veya başka bir rastgele değeri kullanmak gerçekten kötü bir fikirdir. Çözdüğünden daha fazla sorun yaratır (herhangi bir sorunu çözerse bile)
Rob

MD5 değeri mutlak en kötü olasılıktır çünkü iki farklı değerin veya veri kümesinin aynı MD5 değerini üretmesi olasıdır. Bu yüzden buna çözüm demezdim.
David
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.