자동 증분 기본 키 재정렬 / 재설정


127

자동 증분 기본 키가있는 MySQL 테이블이 있습니다. 테이블 중간에서 일부 행을 삭제했습니다. 이제 예를 들어 ID 열에 12, 13, 14, 19, 20과 같은 것이 있습니다. 15, 16, 17 및 18 행을 삭제했습니다.

연속성을 갖도록 기본 키를 재 할당 / 재설정 / 재주문하고 싶습니다 (예 : 19 a 15, 20 a 16 등).

내가 어떻게 해?

답변:


95

기본 키 열을 삭제하고 다시 만들 수 있습니다. 그런 다음 모든 ID를 순서대로 다시 할당해야합니다.

그러나 이것은 아마도 대부분의 상황에서 나쁜 생각입니다. 이 테이블에 외래 키가있는 다른 테이블이 있으면 작동하지 않습니다.


이 테이블의 외래 키를 보유한 다른 테이블이 있지만 프로젝트를 시작하기 때문에 괜찮습니다. 감사합니다!
Jonathan

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

1
mySQL Doc은 이에 대해 다음과 같이 권고한다 : "SET 문 이외의 일반적인 규칙으로서, 사용자 변수에 값을 할당하고 같은 명령문 내에서 값을 읽지 않아야합니다. 예를 들어, 변수를 증가 시키려면 다음과 같이하십시오 : SET @a = @a + 1; SELECT와 같은 다른 명령문의 경우 예상 한 결과를 얻을 수 있지만 이것이 보장되지는 않습니다. 다음 명령문에서는 MySQL이 @a를 먼저 평가 한 다음 할당을 수행한다고 생각할 수 있습니다. 둘째 : SELECT @a, @a : = @ a + 1, ...; 그러나 사용자 변수와 관련된 표현식의 평가 순서는 정의되어 있지 않습니다. "
ReverseEMF

3
@ReverseEMF : 아니요. 할당 순서는 MySQL 표현식에서 고정되어 있습니다. 인용 한 바에 따르면, MySQL 설명서는 변수를 여러 번 독립적으로 사용하는 것에 대해 조언합니다. 위의 경우 표현식의 평가는 단일 할당 표현식``users .id` = @count : = @count + 1 ''때문에 사전 정의 된 순서로 발생해야합니다 . 문서에서 : "오른쪽의 값은 리터럴 값, 값을 저장하는 다른 변수 또는 스칼라 값을 생성하는 모든 법적 표현
Anshul

1
이것은 매우 비싼 진술입니까? 멀티 기가 바이트 테이블에서 어떻게 수행됩니까? 내 ibdata1 (긴 트랜잭션)을 폭파하고 테이블을 너무 오랫동안 차단하는 것이 두렵습니다.
Stefan

1
@Stefan + 2GB의 데이터가있는 다른 키를 참조하는 외래 키가있는 테이블 (5MB)에서이 스크립트는 5 분 이상 걸렸습니다. 시스템에는 ssd가 있으므로 많은 도움이되었다고 가정합니다. FK는 ON UPDATE CASCADE를했다
fernandezr

60

내 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;

584k 개의 행이있는 MyISAM 테이블에서는 약 7.3 초가 걸렸습니다.
user1278519

3
나는 100 표를 가지고 있다면 그것을 이해 나있는 원조 같은 멍청한 놈에 대한 SQL 문을 분해하기 때문에 나는 모든 시간을이를 투표 것이다
repzero

1
두 번째 줄은 필요하지 않습니까, 아니면 제가 틀렸습니까? 그것은 1부터 시작합니다. InnoDB의 경우 나에게 해냈습니다.
Thielicious

두 번째 줄은 필요하지 않습니다.
KawaiKx

1
@ JorgeAugustoMorêradeMoura 기록의 순서는 변경되지 않습니다
Ryan

31

이 쿼리를 간단히 사용할 수 있습니다

alter table abc auto_increment = 1;

2
이 경우에는 작동하지 않습니다. ISAM 테이블의 경우 autoinc 값을 max (id) + 1로 설정합니다. InnoDB의 경우 아무 작업도 수행하지 않습니다. 자동 증가 변경 테이블 변경 문서를 참조하십시오 dev.mysql.com/doc/refman/5.0/en/alter-table.html을
lreeder

3
innodb의 5.6 이후 동작에서 @Ireeder는 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

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의 경우 다음을 수행하십시오 (테이블에서 모든 레코드를 제거하고 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 속성을 제거하는 것입니다. 그런 다음 다른 alter 문을 실행하고 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.....but 당신이 문제에 대해 '오류 코드 : 1265 데이터 열에 대해 잘립니다'실행하면 '1 행에서'ID를 ... 그리고 실행 다음과 같은. 업데이트 쿼리에서 무시를 추가합니다.

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

MD5 값은 두 가지 다른 값 또는 데이터 집합이 동일한 MD5 값을 생성 할 수 있기 때문에 최악의 가능성입니다. 그래서 나는 그것을 해결책이라고 부르지 않을 것입니다.
David
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.