Автоматическое увеличение после удаления в MySQL


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

Я:

table: course
fields: courseID, courseName

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

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

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


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

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

16 58

16 ответов:

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

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

сделайте шаг назад и спросите"почему вам нужно повторно использовать ключевые значения? " Do unsigned INT (или BIGINT) не обеспечивают достаточно большое пространство ключей?

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

ALTER TABLE foo AUTO_INCREMENT=1

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


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

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

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

попробуй :

SET @num := 0;

обновить your_table SET id = @num : = (@num+1);

ALTER TABLE tableName AUTO_INCREMENT = 1;

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

пример : до

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

таким образом, таблица будет отображать массив: 1,2,4,5

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

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

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

но

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

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

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

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

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

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

set @rank = 0;
update tbl a join (select id, @rank:=@rank+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

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

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

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

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

клиенты ранжируются по количеству потраченных средств.

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

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

DELETE FROM table;
ALTER TABLE table AUTO_INCREMENT = 1;

отметим, что ответ Дарина Димитрова объясните очень хорошо AUTO_INCREMENT и его использование. Взгляните туда прежде чем сделать что-то, о чем вы можете пожалеть.

PS: сам вопрос больше "Why you need to recycle key values?" и ответ Дольфа покроет.

Я получил очень простой, но сложный метод.

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

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

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

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

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

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

ALTER TABLE table_name DROP column_name;
ALTER TABLE table_name ADD column_name int not null auto_increment primary key first;

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

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

рассмотрим следующий пример:

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

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

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

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

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

вот функция, которая исправит вашу проблему

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