Как найти следующий бесплатный уникальный 4-значный номер - PullRequest
0 голосов
/ 20 октября 2011

В моем приложении дБ у меня есть требование для уникального, четырехзначного числового поля для каждого клиента. До 9999 года я мог просто использовать автоинкременты, но после этого мне придется повторно использовать количество удаленных клиентов (в определенный момент времени не будет более 5000 клиентов, но в течение срока службы может быть более 9999 клиентов). система).

Вопрос 1: Существует ли (My) оператор SQL для поиска следующего свободного многоразового номера?

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

Ответы [ 5 ]

7 голосов
/ 20 октября 2011

Вам лучше хранить таблицу со всеми 10 000 возможных значений и пометкой «в использовании» на каждом. Таким образом, освобождение номера для повторного использования является простым обновлением для установки «inuse = false».

Также делает поиск наименьшего доступного значения простым

SELECT idstring
FROM idstringtable
ORDER BY idstring ASC
WHERE (available = 1)
LIMIT 1

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

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

2 голосов
/ 20 октября 2011

Если вы ДОЛЖНЫ использовать эту модель (и я бы порекомендовал против нее), то я бы создал пул «доступных» номеров, а при создании учетной записи просто забрал ТОП 1 из этого.Затем, когда пользователь удален, верните номер в пул.

1 голос
/ 20 октября 2011

Рекомендации по использованию отдельной таблицы для отслеживания используемых идентификаторов будут работать, но если вы не хотите использовать отдельную таблицу для отслеживания используемых идентификаторов, вы можете выполнить самостоятельное объединение, чтобы найти пробел в числах идентификаторов.,Самостоятельное соединение довольно просто:

select top 1 t1.id + 1
  from table t1
  left join table t2 on t1.id = t2.id - 1
 where t1.id < 10000
   and t2.id is null

В MS SQL Server я использую TOP 1, чтобы получить наилучший результат, но в MySQL это может быть другой синтаксис.

1 голос
/ 20 октября 2011

Это найти первый доступный слот:

select i1.id + 1 as FirstAvailable
from issues i1 left join issues i2 on (i1.id = i2.id - 1)
where i2.id is null
limit 1

Это было выполнено для рабочего экземпляра Redmine, чтобы найти первый отсутствующий идентификатор. Отрегулируйте в соответствии с вашими потребностями.

0 голосов
/ 05 июня 2018

Приведенный выше ответ (от Адриана Карнейру) является фантастическим и работает, если в таблице не используется другое поле в качестве первичного ключа и НЕ имеется ключа для «id».

Имеется таблица с первичным ключом ID пользователя: -

MariaDB [unixua]> select userid, uid from accounts;
+---------+----------+
| userid  | uid      |
+---------+----------+
| acc0001 | 89814678 |
| acc0002 | 38000474 |
| acc0005 | 38000475 |
| acc0017 | 38000478 |
+---------+----------+
4 rows in set (0.00 sec)

Мы ожидаем, что самый низкий бесплатный номер будет 38000476.

MariaDB [unixua]> SELECT t1.uid +1 FROM accounts t1 
LEFT JOIN accounts t2 ON (t1.uid +1 = t2.uid) 
WHERE t2.uid IS NULL AND t1.uid>38000474 LIMIT 1;
+-----------+
| t1.uid +1 |
+-----------+
|  89814679 |
+-----------+
1 row in set (0.00 sec)

Но, поскольку MySQL / MariaDB выбирает их в порядке первичного ключа, это дает сбой и дает следующий наивысший после "acc001". Добавляя ключ к столбцу uid и выполняя только SELECT для столбца «uid», MySQL / MariaDB будет использовать индекс для извлечения данных (вместо чтения таблицы). Поскольку индекс «упорядочен», результат будет другим: -

MariaDB [unixua]> alter table accounts add unique index (uid);
Query OK, 0 rows affected (0.01 sec)
Records: 0  Duplicates: 0  Warnings: 0

MariaDB [unixua]> SELECT t1.uid +1 FROM accounts t1 
LEFT JOIN accounts t2 ON (t1.uid +1 = t2.uid) 
WHERE t2.uid IS NULL AND t1.uid>38000474 LIMIT 1;
+-----------+
| t1.uid +1 |
+-----------+
|  38000476 |
+-----------+
1 row in set (0.00 sec)

Убедитесь, что в вашей таблице есть ключ для поля Идентификатор клиента (и это поле Идентификатор клиента является числовым).

Это работает, потому что оптимизатор может извлекать все необходимые данные для выбора из индекса (aka accounts.myi, а не accounts.myd), а не данные таблицы.

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