2010-02-06 3 views
53

У меня есть таблица MySQL с полем первичного ключа, на котором есть AUTO_INCREMENT. После прочтения других сообщений здесь я заметил людей с одинаковой проблемой и с разными ответами. Некоторые рекомендуют не использовать эту функцию, другие утверждают, что она не может быть «исправлена».Auto Increment после удаления в MySQL

у меня есть:

table: course 
fields: courseID, courseName 

Пример: число записей в таблице: 18. Если удалить запись 16, 17 и 18 - я бы ожидать очередной рекорд вошел иметь courseID 16, однако это будет 19, потому что последний введенный идентификатор курса был равен 18.

Мои знания SQL не удивительны, но все равно нужно обновить или обновить этот счет с помощью запроса (или настройки в интерфейсе phpMyAdmin)?

Эта таблица будет относиться к другим в базе данных.

Учитывая все советы, я решил проигнорировать эту «проблему». Я просто удалю и добавлю записи, в то время как автоматическое приращение сделает это. Я думаю, это не имеет большого значения, каково число, поскольку оно используется только как уникальный идентификатор и не имеет (как упоминалось выше) бизнес значение.

Для тех, кого я, возможно, путал с моим оригинальным сообщением: я не хочу использовать это поле, чтобы узнать, сколько записей у меня есть. Я просто хотел, чтобы база данных выглядела аккуратно и имела немного более согласованность.

+3

, что вы ожидали бы случиться, если вы удалили только запись 16? –

+0

Хорошая точка! Я должен был упомянуть. В идеале, сдвиньте все до одного? – OmidTahouri

+0

Я столкнулся с проблемой, которая в некотором роде противоречит вашей проблеме. Другими словами, у меня есть таблица «ENTITY» и таблица «ENTITY_LOG». Каждый раз, когда я вставляю, обновляю или удаляю что-либо из таблицы «ENTITY», я регистрирую эту активность в таблице «ENTITY_LOG» вместе с идентификатором «Id». Недавно пользователь удалил кучу записей в таблице «ENTITY»; и соответствующие записи журнала были сделаны в таблице журналов. Сегодня, когда другой пользователь попытался добавить новую запись в таблицу «ENTITY», сгенерированный «Id» оказался таким же, как ранее удаленный объект! Я использую JdbcTemplate и InnoDB. –

ответ

57

То, что вы пытаетесь сделать, звучит опасно, поскольку это не намеренное использование AUTO_INCREMENT.

Если вы действительно хотите найти наименьшее неиспользованное значение ключа, не используйте AUTO_INCREMENT и управляйте своими ключами вручную. Однако это НЕ рекомендуемая практика.

Сделайте шаг назад и спросить «почему вам нужно переработать ключевые ценности?» У знака INT (или BIGINT) не обеспечивают достаточно большой пространства ключей?

У вас действительно будет больше, чем 18,446,744,073,709,551,615 уникальных записей в течение срока вашего приложения?

+0

Вы правы. Лучше проигнорировать это. Учитывая это только для задания, я не буду входить в большие числа, и жизнь очень короткая. – OmidTahouri

+3

согласны с высокой опасностью по ряду причин. Во-первых, в многопользовательской системе у вас может быть много, сотни, тысячи обновлений в секунду и попытка переписать auto inc может либо замедлить работу системы, либо скомпрометировать ее. Двое других разработчиков не знали бы, что вы были = делаете это, возможно, и записываете записи через идентификатор, чтобы развратить систему. – PurplePilot

+0

Хорошие баллы. Ответ заставил меня подумать дважды. Я для одного не искал пробелов в auto_incr. потому что я собирался каким-то образом перебирать идентификаторы. Но я думаю, что лучше просто прокрутить строки :) –

2

вы можете выбрать идентификаторы, как так:

set @rank = 0; 
select id, @rank:[email protected]+1 from tbl order by id 

результатом является список идентификаторов, а также их позиции в последовательности.

вы также можете сбросить идентификаторы, как так:

set @rank = 0; 
update tbl a join (select id, @rank:[email protected]+1 as rank from tbl order by id) b 
    on a.id = b.id set a.id = b.rank; 

вы также можете просто распечатать первый неиспользуемый так:

select min(id) as next_id from ((select a.id from (select 1 as id) a 
    left join tbl b on a.id = b.id where b.id is null) union 
    (select min(a.id) + 1 as id from tbl a left join tbl b on a.id+1 = b.id 
    where b.id is null)) c; 

после каждой вставки, вы можете сбросить auto_increment:

alter table tbl auto_increment = 16 

или явно задать значение идентификатора при выполнении вставки:

insert into tbl values (16, 'something'); 

Обычно это необязательно, у вас есть count(*) и возможность создания номера ранжирования в ваших результирующих наборах. типичным ранжированием может быть:

set @rank = 0; 
select a.name, a.amount, b.rank from cust a, 
    (select amount, @rank:[email protected]+1 as rank from cust order by amount desc) b 
    where a.amount = b.amount 

клиентов, оцененных по затраченной сумме.

26
ALTER TABLE foo AUTO_INCREMENT=1 

Если вы удалили последние записи, которые должны установить его для использования следующей самой низкой доступной. Как и в случае, если уже нет 19, удаление 16-18 приведет к сбросу автоинкремента для использования 16.


EDIT: я пропустил немного о PHPMyAdmin. Вы можете установить его там тоже. Перейдите на экран таблицы и перейдите на вкладку операций. Там есть поле AUTOINCREMENT, в котором вы можете установить все, что вам нужно вручную.

+1

OP МОЖЕТ это сделать, но он не должен. Вы должны действительно пересмотреть этот совет, учитывая то, что пытается сделать OP. –

+9

Это не мое место, чтобы рассказать ему, как выложить свою базу данных или как сделать свою бизнес-логику. Он также упомянул в своем посте, что он читает другие сообщения/страницы, в которых говорится, что это плохая идея, поэтому он знает, что это не рекомендуемая практика, но в любом случае продолжит ее. – monksp

+3

Это самый прямой ответ, который в настоящее время предоставляется прямому вопросу айзера. В этом нет никакого «совета». – Air

13

Основные ключи автоинкремента в базе данных используются для однозначной идентификации данной строки и не должны предоставляться Значение. Поэтому оставьте первичный ключ как есть и добавьте другой столбец, называемый, например, courseOrder. Затем, когда вы удаляете запись из базы данных, вы можете отправить дополнительный оператор UPDATE, чтобы уменьшить столбец courseOrder всех строк, у которых courseOrder больше, чем тот, который вы сейчас удаляете.

В качестве побочного примечания вы никогда не должны изменять значение первичного ключа в реляционной базе данных, так как могут быть другие таблицы, которые ссылаются на него как на внешний ключ, и его изменение может нарушать ссылочные ограничения.

+0

он ищет, чтобы поддерживать счет, а не заказывать. UPDATE кажется ненужным. –

+0

Ну, если он хочет сохранить счет, тогда нет необходимости добавлять дополнительные столбцы. Простая функция агрегации 'count' выполнит эту работу. –

+0

Право, это то, к чему я пытался добраться. –

0

Вы можете использовать клиентское программное обеспечение/скрипт mysql, чтобы указать, где должен начинаться первичный ключ после удаления необходимых записей.

3

Вы не должны полагаться на идентификатор AUTO_INCREMENT, чтобы рассказать вам, сколько записей у вас в таблице. Вы должны использовать SELECT COUNT(*) FROM course. ID, чтобы однозначно идентифицировать курс и могут использоваться как ссылки в других таблицах, поэтому вы не должны повторять идентификаторы и не должны пытаться сбросить поле автоматического приращения.

+0

Думаю, он думает, что это какая-то ошибка. MySQL 20 лет. Это определенно не надзор. Существует очень веская причина, по которой автоинкремент не перерабатывает ключи. Ты совершенно прав Майк. –

2

У меня очень простой, но сложный метод.

При удалении строки вы можете сохранить идентификаторы в другую временную таблицу. После этого, когда вы вставляете новые данные в основную таблицу, вы можете искать и выбирать идентификаторы из временной таблицы. Поэтому используйте проверку здесь. Если временная таблица не имеет идентификаторов, затем вычисляет максимальный идентификатор в основной таблице и устанавливает новый ID как: new_ID = old_max_ID+1.

NB: Вы не можете использовать функцию автоматического увеличения.

2

Я пришел сюда в поисках ответа на вопрос название "MySQL - Auto Increment after delete" но я только мог найти ответ на что в вопросах

с помощью что-то вроде:

DELETE FROM table; 
ALTER TABLE table AUTO_INCREMENT = 1; 

Обратите внимание, что Darin Dimitrov's answer объясните действительно хорошо AUTO_INCREMENT и его использование. Взгляните туда, прежде чем делать что-то, о чем вы можете пожалеть.

PS: вопрос сам по себе более "Why you need to recycle key values?" и Dolph's answer крышка это.

6

Try:

SET @num: = 0;

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

ALTER TABLE tableName AUTO_INCREMENT = 1;

Это сбросит значение автоинкремента, а затем подсчитает каждую строку, пока для него будет создано новое значение.

пример: перед тем

  • 1: первое значение здесь
  • 2: Значение второго здесь
  • X: удалено значение
  • 4: Остальная часть таблицы
  • 5: Остальное от остальных ..

поэтому таблица отобразит массив: 1,2,4,5

Пример: ПОСЛЕ (если использовать эту команду вы получите)

  • 1: первое значение здесь
  • 2: Значение второго здесь
  • 3: Остальная часть таблицы
  • 4 : остальная часть остатка

Отсутствие следа удаляемого значения, а остальная часть приращения продолжается с этим новым счетом.

НО

  1. Если где-то на что-то кода использовать autoincremented значение ... может быть, это приписывание вызовет проблемы.
  2. Если вы не используете это значение в своем коде, все должно быть в порядке.
+0

Если вы хотите сохранить старые значения и установить auto_increment на максимальное значение, то вам нужно найти максимальное значение: 1. Закажите их и возьмите значение последней строки/ 2. а затем установите для этого auto increment максимальное значение +1 в вашем коде. – Claod

0

То, что вы пытаетесь сделать, очень опасно. Подумайте об этом внимательно. Существует очень веская причина для поведения автоматического приращения по умолчанию.

Рассмотрим это:

запись удаляется в одну таблицу, которая имеет связь с другой таблицей. Соответствующая запись во второй таблице не может быть удалена для целей аудита. Эта запись становится сиротой из первой таблицы. Если новая запись вставляется в первую таблицу и используется последовательный первичный ключ, эта запись теперь привязана к сироте. Очевидно, это плохо. При использовании автоматической инкрементной PK всегда гарантируется идентификатор, который никогда не использовался раньше. Это означает, что сироты остаются сиротами, что является правильным.

0

Я могу придумать множество сценариев, в которых вам может понадобиться сделать это, особенно во время процесса миграции или разработки. Например, мне просто нужно было создать новую таблицу, перекрестно соединяя две существующие таблицы (как часть сложного процесса настройки), а затем мне нужно было добавить первичный ключ после события. Вы можете удалить существующий столбец первичного ключа, а затем сделать это.

ALTER TABLE my_table ADD `ID` INT NOT NULL AUTO_INCREMENT FIRST, ADD PRIMARY KEY (`ID`); 

Для живой системы, это не очень хорошая идея, особенно если есть и другие таблицы с внешними ключами, указывающих на него.

0

Фактически есть способ исправить это. Сначала вы удалите auto_incremented столбец первичного ключа, а затем добавить его снова, как это:

ALTER TABLE table_name DROP column_name; 
ALTER TABLE table_name ADD column_name int not null auto_increment primary key first; 
0
if($id == 1){ // deleting first row 
      mysqli_query($db,"UPDATE employees SET id=id-1 WHERE id>1"); 
     } 
     else if($id>1 && $id<$num){ // deleting middle row 
      mysqli_query($db,"UPDATE employees SET id=id-1 WHERE id>$id"); 
     } 
     else if($id == $num){ // deleting last row 
      mysqli_query($db,"ALTER TABLE employees AUTO_INCREMENT = $num"); 
     } 
     else{ 
      echo "ERROR"; 
     } 

     mysqli_query($db,"ALTER TABLE employees AUTO_INCREMENT = $num"); 
+0

MySQL - это реляционная база данных. Когда существует несколько таблиц, должно быть отношение, определенное между таблицами. И это делается с использованием столбцов идентификаторов. Проблема с этим подходом заключается в том, что если вы начнете перенумеровать индексы таблицы, то будут действовать эффекты на всех таблицах, с которыми она связана. – liamvictor

+0

это работает для меня – user3351200

0

Вы можете думать о том, чтобы триггер после удаления, так что вы можете обновить значение Autoincrement и значение идентификатора всех строк, которые не похожи на то, что вы хотели видеть.

Таким образом, вы можете работать с одной и той же таблицей, и автоматическое приращение будет автоматически исправлено всякий раз, когда вы удаляете строку, триггер будет ее исправлять.

+0

[ссылка] (http://www.tech-recipes.com/rx/41468/sql-server-coding-the-after-delete-trigger-in-sql-server/) –

0

Его определенно не рекомендуем. Если у вас есть большая база данных с несколькими таблицами, возможно, вы сохранили идентификатор пользователя как id в таблице 2. Если вы измените таблицу 1, то, вероятно, предполагаемый идентификатор пользователя не будет являться предполагаемой таблицей 2 id.

0

здесь функцию, исправить вашу проблему

public static void fixID(Connection conn, String table) { 

    try { 
     Statement myStmt = conn.createStatement(); 
     ResultSet myRs; 
     int i = 1, id = 1, n = 0; 
     boolean b; 
     String sql; 

     myRs = myStmt.executeQuery("select max(id) from " + table); 
     if (myRs.next()) { 
      n = myRs.getInt(1); 
     } 
     while (i <= n) { 
      b = false; 
      myRs = null; 
      while (!b) { 
       myRs = myStmt.executeQuery("select id from " + table + " where id=" + id); 
       if (!myRs.next()) { 
        id++; 
       } else { 
        b = true; 
       } 
      } 

      sql = "UPDATE " + table + " set id =" + i + " WHERE id=" + id; 
      myStmt.execute(sql); 
      i++; 
      id++; 
     } 

    } catch (SQLException e) { 
     e.printStackTrace(); 
    } 
}