MySQL найти наименьший + уникальный идентификатор доступны - PullRequest
23 голосов
/ 16 февраля 2011

У меня есть идентификатор столбца и что-то вроде 1000 элементов, некоторые из них были удалены как id=90, id=127, id=326

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

это похоже на min(ID), но я хочу найти только те идентификаторы, которых нет в моей базе данных, поэтому, если я удалю элемент с ID = 90, в следующий раз, когда я нажму на ДОБАВИТЬ ПУНКТ, я вставлю его как id = 90

Ответы [ 7 ]

37 голосов
/ 16 февраля 2011

Вы можете получить минимальный доступный идентификатор, используя этот запрос:

SELECT MIN(t1.ID + 1) AS nextID
FROM tablename t1
   LEFT JOIN tablename t2
       ON t1.ID + 1 = t2.ID
WHERE t2.ID IS NULL

Что он делает, так это соединяет таблицу с собой и проверяет, равен ли min+1 ID null или нет. Если это ноль, то этот идентификатор доступен. Предположим, у вас есть таблица, где ID:
1
2
5 * +1010 * 6

Тогда этот запрос выдаст вам результат 3, который вы хотите.

5 голосов
/ 16 февраля 2011

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

Например, если вы повторно используете идентификаторы, ссылки из поисковых систем могут указывать на что-то совершенно не связанное с тем, что находится в поискеindex - в этом случае лучше показывать ошибку «not found».

3 голосов
/ 16 февраля 2011

Противопоказано использовать суррогатные ключи для повторного использования идентификаторов.

Суррогатный ключ хорош тем, что он идеализирует саму запись, а не какой-то объект в реальной жизни.Если запись пропала, идентификатор тоже пропал.

Опытные разработчики БД не боятся нехватки чисел, потому что они знают, сколько веков нужно, чтобы, скажем, длинные целые числа.

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

Дополнительная информация: Суррогатные ключи

2 голосов
/ 16 февраля 2011

запрос как :

SELECT MIN(tableFoo.uniqueid + 1) AS nextID
FROM tableFoo
LEFT JOIN tableFoo tf1
       ON tableFoo.uniqueid + 1 = tf1.uniqueid
WHERE tf1.uniqueid IS NULL
1 голос
/ 19 ноября 2015

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

UPDATE table SET data=" ", removed = TRUE WHERE id = ##

(кстати, ## - это фактический идентификатор). Затем вы можете

SELECT * FROM table WHERE removed = TRUE ORDER BY id ASC

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

1 голос
/ 11 октября 2015

Обратите внимание, что ответы от shamittomar и Haim Evgi не работают, если самый низкий идентификатор свободен. Чтобы разрешить пополнение минимального идентификатора, предварительно проверьте, доступен ли он:

SELECT TRUE FROM tablename WHERE ID = 1;

Если это что-то возвращает, тогда ID 1 не является свободным, и вы должны использовать их ответ. Но если ID 1 свободен, просто используйте его.

0 голосов
/ 28 апреля 2016

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

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

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

Здесь вычисляется полное соединение между полными значениями t1 и t2, а затем сообщается, каков минимум этих объединений.По сути, вы заботитесь только о первом NULL t1, который будет найден, независимо от того, является ли он на самом деле наименьшим или нет.

Таким образом, вы бы взяли MIN и добавили LIMITвместо 1.

edit: Поскольку он не является первичным ключом, вам также необходимо проверить, не является ли он нулевым, поскольку поле первичного ключа не может быть нулевым

SELECT t1.ID + 1 AS nextID
FROM tablename t1
   LEFT JOIN tablename t2
       ON t1.ID + 1 = t2.ID
WHERE t2.ID IS NULL
AND t1.ID IS NOT NULL
LIMIT 1

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

...