как найти дыры в столбце auto_increment?

когда я DELETE, например, идентификатор 3, у меня есть это:

id | name
 1 |
 2 |    
 4 |
 5 |
 ...

теперь я хочу найти отсутствующие идентификаторы, потому что я хочу снова заполнить идентификатор:

INSERT INTO xx (id,...) VALUES (3,...)

есть ли способ поиска «дыр» в индексе auto_increment?

Благодарность!


person skyline26    schedule 17.04.2012    source источник
comment
почему ты хочешь сделать это? Такие дыры нормальны в повседневной работе базы данных и не должны вызывать беспокойства. Если это связано с каким-то ошибочным представлением об эстетике, сопротивляйтесь этому.   -  person Oded    schedule 17.04.2012
comment
Тебе не следует. Auto_increment должен просто выполнять свою работу, а это значит, что можно делать дыры. Если вы начнете возиться с этим, вы столкнетесь с проблемами позже. Просто позвольте им быть.   -  person Nanne    schedule 17.04.2012
comment
Не говоря уже о том, что если удаленный идентификатор все еще где-то упоминается, например, через ссылку с закладкой / необновленную таблицу, то добавление новой строки с этим идентификатором приведет к непреднамеренным проблемам. Как заявил Одед, Нанне просто оставьте ИИ делать свою работу.   -  person Simon at My School Portal    schedule 17.04.2012
comment
Как говорили другие: вам все равно, и вам не нужно это делать.   -  person a_horse_with_no_name    schedule 17.04.2012
comment
Antijoin к вспомогательному "Таблица чисел" уникальных целочисленных значений.   -  person onedaywhen    schedule 17.04.2012
comment
@a_horse_with_no_name: проблема в том, что даже если кто-то согласен с тем, что значения суррогатного ключа не должны открываться пользователям, никто никогда не предполагает, что рассматриваемый пользователь - это он сам!   -  person onedaywhen    schedule 17.04.2012
comment
удаленные идентификаторы вообще никоим образом не упоминаются ... поэтому идентификатор свободен, и я могу безопасно использовать его повторно.   -  person skyline26    schedule 17.04.2012
comment
хорошо: это не очень хорошая идея... но спасибо за информацию! подскажите какой лучший ответ? хД   -  person skyline26    schedule 17.04.2012


Ответы (5)


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

select t1.id - 1 as missing_id
from mytable t1
left join mytable t2 on t2.id = t1.id - 1
where t2.id is null
person Bohemian♦    schedule 17.04.2012
comment
что делать, если у вас болтливость больше 1? если у вас есть 14, а затем 20, он покажет только 19 - person Diego; 17.04.2012
comment
@Diego Обратите внимание, что мой ответ говорит, что мой запрос найдет максимальное значение пробелов. Вы выясняете, что произойдет, если разрыв больше 1 - person Bohemian♦; 17.04.2012

Целью AUTO_INCREMENT является создание простых уникальных и бессмысленных идентификаторов для ваших строк. Как только вы планируете повторно использовать эти идентификаторы, они перестают быть уникальными (по крайней мере, со временем), поэтому у меня сложилось впечатление, что вы используете не тот инструмент для работы. Если вы решили избавиться от AUTO_INCREMENT, вы можете делать все свои вставки по тому же алгоритму.

Что касается кода SQL, этот запрос сопоставит существующие строки со строками со следующим идентификатором:

SELECT a.foo_id, b.foo_id
FROM foo a
LEFT JOIN foo b ON a.foo_id=b.foo_id-1

E.g.:

 1 NULL
 4 NULL
10 NULL
12 NULL
17 NULL
19   20
20 NULL
24   25
25   26
26   27
27 NULL

Так что легко отфильтровать строки и получить первый пробел:

SELECT MIN(a.foo_id)+1 AS next_id
FROM foo a
LEFT JOIN foo b ON a.foo_id=b.foo_id-1
WHERE b.foo_id IS NULL

Возьмите это как отправную точку, потому что она все еще нуждается в некоторой настройке:

  • Вам необходимо рассмотреть случай, когда наименьшее доступное число является наименьшим возможным.
  • Вам нужно заблокировать таблицу для обработки одновременных вставок.
  • На моем компьютере это чертовски медленно с большими таблицами.
person Álvaro González    schedule 17.04.2012
comment
спасибо за дополнительную информацию (на моем компьютере это чертовски медленно с большими таблицами.) - person skyline26; 17.04.2012

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

insert into XX values (1)
insert into XX values (2)
insert into XX values (4)
insert into XX values (5)
insert into XX values (10)

declare @min int
declare @max int

select @min=MIN(ID) from xx
select @max=MAX(ID) from xx

while @min<@max begin
    if not exists(select 1 from XX where id = @min+1) BEGIN
        print 'GAP: '+ cast(@min +1 as varchar(10))
    END

    set @min=@min+1
end

результат:

GAP: 3
GAP: 6
GAP: 7
GAP: 8
GAP: 9
person Diego    schedule 17.04.2012

Во-первых, я согласен с комментариями о том, что не стоит пытаться затыкать дыры. Вы не сможете найти все дыры с помощью одного оператора SQL. Вам придется перебирать все возможные числа, начиная с 1, пока не найдете дыру. Вы можете написать функцию sql, чтобы сделать это для вас, которую затем можно было бы использовать в функции. Итак, если вы написали функцию с именем find_first_hole, вы могли бы вызвать ее во вставке, например:

INSERT INTO xx (id, ...) VALUES (find_first_hole(), ...)
person davidethell    schedule 17.04.2012

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

person wildplasser    schedule 17.04.2012