เรียงลำดับใหม่ / รีเซ็ตคีย์หลักที่เพิ่มขึ้นอัตโนมัติ


127

ฉันมีตาราง MySQL ที่มีคีย์หลักแบบเพิ่มอัตโนมัติ ฉันลบบางแถวตรงกลางตาราง ตอนนี้ฉันมีบางอย่างเช่นนี้ในคอลัมน์ ID: 12, 13, 14, 19, 20 ฉันลบแถว 15, 16, 17 และ 18

ฉันต้องการกำหนดใหม่ / รีเซ็ต / เรียงลำดับคีย์หลักใหม่เพื่อให้ฉันมีความต่อเนื่องเช่นสร้าง 19 a 15, 20 a 16 และอื่น ๆ

ฉันจะทำมันได้อย่างไร?

คำตอบ:


95

คุณสามารถวางคอลัมน์คีย์หลักและสร้างใหม่ได้ จากนั้นควรกำหนดรหัสทั้งหมดใหม่ตามลำดับ

อย่างไรก็ตามนี่อาจเป็นความคิดที่ไม่ดีในสถานการณ์ส่วนใหญ่ หากคุณมีตารางอื่นที่มีคีย์แปลกปลอมอยู่ในตารางนี้ก็จะไม่ทำงานอย่างแน่นอน


ฉันมีตารางอื่นที่มีคีย์ต่างประเทศอยู่ในตารางนี้ แต่ฉันเพิ่งเริ่มโปรเจ็กต์ดังนั้นมันก็โอเคสำหรับฉัน .. ขอบคุณ!
Jonathan

65
มันอาจจะดีที่สุดในระยะยาวหากคุณพยายามและเริ่มยอมรับว่า ID ของคุณจะไม่เรียงตามลำดับเสมอไปมิฉะนั้นเมื่อคุณเริ่มทำงานในโปรเจ็กต์ใหญ่ ๆ มันจะทำให้บ้าคลั่ง!
Ciaran McNulty

8
แก้ไขตาราง 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;

สำหรับ MySQLs MAX(id) + 1มันจะตั้งค่าให้


การใช้คีย์ต่างประเทศเป็นวิธีแก้ปัญหาที่ยอดเยี่ยมสำหรับโต๊ะของฉันซึ่งมีการแทรกและลบขยะจำนวนมากและฉันต้องการประหยัดพื้นที่ดัชนี
mukunda

1
mySQL Doc ให้คำแนะนำกับสิ่งนี้: "ตามกฎทั่วไปนอกเหนือจากคำสั่ง SET คุณไม่ควรกำหนดค่าให้กับตัวแปรผู้ใช้และอ่านค่าภายในคำสั่งเดียวกันตัวอย่างเช่นหากต้องการเพิ่มตัวแปรก็ไม่เป็นไร: SET @a = @a + 1 สำหรับคำสั่งอื่น ๆ เช่น SELECT คุณอาจได้ผลลัพธ์ตามที่คาดหวัง แต่ไม่รับประกันในคำสั่งต่อไปนี้คุณอาจคิดว่า MySQL จะประเมิน @a ก่อนจากนั้นจึงทำการมอบหมาย วินาที: SELECT @a, @a: = @ a + 1, ... ; อย่างไรก็ตามลำดับของการประเมินนิพจน์ที่เกี่ยวข้องกับตัวแปรของผู้ใช้ไม่ได้กำหนดไว้ "
ReverseEMF

3
@ReverseEMF: ไม่ลำดับของการมอบหมายได้รับการแก้ไขในนิพจน์ MySQL จากสิ่งที่คุณยกมาเอกสารประกอบของ MySQL จะให้คำแนะนำกับการใช้ตัวแปรหลายตัวโดยอิสระ ในกรณีข้างต้นการประเมินนิพจน์จะเกิดขึ้นตามลำดับที่กำหนดไว้ล่วงหน้าเนื่องจากนิพจน์การกำหนดค่าเดียว "ผู้ใช้.id" = @count: = @count + 1 " จากเอกสาร: "ค่าทางด้านขวามืออาจเป็นค่าตามตัวอักษรตัวแปรอื่นที่จัดเก็บค่าหรือนิพจน์ทางกฎหมายใด ๆ ที่ให้ค่าสเกลาร์"
Anshul

1
งบแพงมากขนาดนี้เลยเหรอ? มันจะทำงานอย่างไรในตารางหลายกิกะไบต์ ฉันกลัวว่า ibdata1 ของฉันจะระเบิด (การทำธุรกรรมที่ยาวนาน) และการบล็อกตารางนานเกินไป
Stefan

1
@Stefan บนโต๊ะ (5MB) พร้อมคีย์ต่างประเทศที่อ้างอิงอีกอันที่มีข้อมูล + 2GB สคริปต์นี้ใช้เวลาไม่เกินห้านาที ระบบมี 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;

บนตาราง MyISAM ที่มี 584k แถวใช้เวลาประมาณ 7.3 วินาที
user1278519

3
ถ้าฉันได้ 100 โหวตฉันจะโหวตเรื่องนี้ตลอดเวลาเพราะมันแบ่งงบ sql สำหรับ noob อย่างฉันที่ช่วยในการทำความเข้าใจ
repzero

1
บรรทัดที่สองไม่จำเป็นหรือฉันผิด? มันเริ่มต้นด้วย 1 ของตัวเองสำหรับ InnoDB มันทำเพื่อฉัน
Thielicious

บรรทัดที่สองไม่จำเป็น
KawaiKx

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

หากคุณมีตารางอื่นที่มีคีย์แปลกปลอมอยู่ในตารางนี้สิ่งนี้จะทำลายมันหรือไม่?
Kyle Vassella

15
SET  @num := 0;

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

ALTER TABLE your_table AUTO_INCREMENT =1;

ฉันคิดว่าสิ่งนี้จะทำได้


12

หรือจาก PhpMyAdmin ลบแฟล็ก "AutoIncrement" บันทึกตั้งค่าอีกครั้งและบันทึกซึ่งจะรีเซ็ตมัน


ขออภัยฉันไม่สามารถทดสอบกับ phpmyadmin เวอร์ชันปัจจุบันได้ คำตอบของฉันค่อนข้างเก่า ... หากคุณลดคะแนนฉันโปรดแก้ไขได้ไหม
lbrutti


1

ใน phpmyadmin

หมายเหตุ: จะใช้ได้ถ้าคุณลบแถวสุดท้ายไม่ใช่แถวกลาง

ไปที่ตารางของคุณ -> คลิกที่เมนูการทำงาน -> ตัวเลือกตารางไปที่ -> เปลี่ยน AUTO_INCREMENT เป็นไม่จากจุดที่คุณต้องการเริ่ม

การเพิ่มตารางอัตโนมัติของคุณเริ่มต้นจากหมายเลขนั้น

ลองมัน. ใส่คำอธิบายภาพที่นี่


0

คุณสามารถลบฟังก์ชันการเพิ่มอัตโนมัติของคีย์หลักของคอลัมน์นั้นได้ทุกครั้งที่คุณอัปเดตคอลัมน์นั้นให้เรียกใช้แบบสอบถามก่อนที่จะนับแถวทั้งหมดในตารางจากนั้นเรียกใช้ลูปที่วนซ้ำผ่านการนับแถวนั้นโดยแทรกแต่ละค่าลงใน แถวตามลำดับและสุดท้ายเรียกใช้แบบสอบถามโดยแทรกแถวใหม่โดยให้ค่าของคอลัมน์นั้นเป็นจำนวนแถวทั้งหมดบวกหนึ่ง วิธีนี้จะทำงานได้อย่างไม่มีที่ติและเป็นทางออกที่ดีที่สุดสำหรับคนที่พยายามทำสิ่งที่คุณเป็นให้สำเร็จ นี่คือตัวอย่างของรหัสที่คุณอาจใช้สำหรับฟังก์ชัน:

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

ที่นี่ฉันสร้างอาร์เรย์ที่เชื่อมโยงซึ่งฉันได้ต่อท้ายคอลัมน์อันดับด้วยคิวรีภายในคิวรีแบบเลือกซึ่งทำให้แต่ละแถวมีค่าอันดับเริ่มต้นด้วย 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 ให้ทำสิ่งนี้ (สิ่งนี้จะลบระเบียนทั้งหมดออกจากตารางสร้าง 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 ;

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 จากนั้นออกคำสั่งเปลี่ยนแปลงอีกครั้งและใส่ auto_increment กลับไปที่คอลัมน์ การดำเนินการนี้จะรีเซ็ตการนับเป็นสูงสุด +1 ของแถวปัจจุบันและรักษาการอ้างอิงคีย์ต่างประเทศกลับไปที่ตารางนี้จากตารางอื่นในฐานข้อมูลของคุณหรือการใช้คีย์อื่น ๆ สำหรับคอลัมน์นั้น


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

0

ใช้งานได้ - https://stackoverflow.com/a/5437720/10219008 ...แต่ถ้าคุณพบปัญหา 'รหัสข้อผิดพลาด: 1265 ข้อมูลจะถูกตัดทอนสำหรับคอลัมน์' id 'ที่แถว 1' ... จากนั้นเรียกใช้ ดังต่อไปนี้. การเพิ่มการละเว้นในแบบสอบถามการอัปเดต

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

-2

คุณยังสามารถหลีกเลี่ยงการใช้รหัสตัวเลขเป็นคีย์หลักได้อีกด้วย คุณสามารถใช้รหัสประเทศเป็นรหัสหลักหากตารางมีข้อมูลประเทศหรือคุณสามารถใช้ลิงก์ถาวรได้เช่นหากมีบทความ

คุณยังสามารถใช้ค่าสุ่มหรือค่า MD5 ตัวเลือกทั้งหมดนี้มีประโยชน์เป็นของตัวเองโดยเฉพาะใน IT sec รหัสตัวเลขนั้นง่ายต่อการแจกแจง


1
... คุณมีพื้นฐานมาจากอะไร? บางทีอย่าเพิ่งสร้างเพจเช่น "complete_user_info_export.php? userid = 34"? ภายในใช้สตริงหรือสุ่มค่าอื่น ๆ เช่นดัชนี / ตัวระบุเป็นจริงๆความคิดที่ดี มันสร้างปัญหามากกว่าที่จะแก้ได้ (ถ้ามันแก้ปัญหาได้ด้วยซ้ำ)
Rob

ค่า MD5 เป็นความเป็นไปได้ที่เลวร้ายที่สุดเนื่องจากเป็นไปได้ที่ค่าหรือชุดข้อมูลที่แตกต่างกันสองค่าจะสร้างค่า MD5 เหมือนกัน ดังนั้นฉันจะไม่เรียกว่าวิธีแก้ปัญหา
เดวิด
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.