Я работаю над игрой, в которой в какой-то момент задействованы машины. У меня есть таблица MySQL с именем «cars», содержащая данные о транспортных средствах, включая столбец «plate», в котором хранятся номерные знаки для транспортных средств.
А вот часть, с которой у меня проблемы. Перед созданием нового автомобиля мне нужно найти неиспользуемый номерной знак - это должна быть случайная буквенно-цифровая строка из 8 символов. Как я добился этого, я использовал цикл while в Lua, языке, на котором я программирую, для генерации строк и запроса БД, чтобы узнать, используется ли он. Однако по мере увеличения количества автомобилей я ожидаю, что это станет еще более неэффективным, чем сейчас. Поэтому я решил попробовать решить эту проблему с помощью запроса MySQL.
Требуемый мне запрос должен просто генерировать 8-символьную буквенно-цифровую строку, которой еще нет в таблице. Я снова подумал о подходе создания и проверки цикла, но я не ограничиваю этот вопрос только на тот случай, если есть более эффективный. Мне удалось сгенерировать строки, определив строку, содержащую все разрешенные символы, и случайным образом подстроку, и не более того.
Любая помощь приветствуется.
Ответы:
Эта проблема состоит из двух очень разных подзадач:
В то время как случайность довольно легко достигается, уникальность без цикла повтора - нет. Это заставляет нас в первую очередь сосредоточиться на уникальности. Неслучайной уникальности легко добиться с помощью
AUTO_INCREMENT
. Таким образом, можно использовать псевдослучайное преобразование, сохраняющее уникальность:RAND(N)
сам!Последовательность случайных чисел, созданная одним и тем же семенем, гарантированно будет
INT32
Итак, мы используем подход @ AndreyVolk или @ GordonLinoff, но с засеянным
RAND
:например, Ассумин
id
- этоAUTO_INCREMENT
столбец:источник
RAND(LAST_INSERT_ID()); UPDATE vehicles (...) , rand()*36+1, (...)
(иначе он возвращает 8 раз один и тот же символ). Как мы можем быть уверены, что 8 последовательных вызовов кrand()
гарантированно вернут другую последовательность, если они инициализированы другим семенем?FLOOR()
параметры второй подстроки: в…
substring('ABC … 789', floor(rand(@seed:= … )*36+1), 1),
…
некоторых случаях подстрока пыталась выбрать символ 36.9, что при округлении до 37 не приводило к выбору символа.floor()
. Этот sqlfiddle показывает, что дубликаты создаются для трехсимвольных строк.193844
и775771
вашего алгоритма будет сгенерирована одна и та же строкаT82X711
( демонстрация ).Я бы не стал беспокоиться о вероятности столкновения. Просто сгенерируйте случайную строку и проверьте, существует ли она. Если это так, попробуйте еще раз, и вам не нужно будет делать это чаще, чем пару раз, если вам не назначено огромное количество номеров.
Другое решение для генерации псевдослучайной строки длиной 8 символов в чистом (My) SQL:
Вы можете попробовать следующее (псевдокод):
Поскольку этот пост получил неожиданный уровень внимания, позвольте мне выделить комментарий ADTC : приведенный выше фрагмент кода довольно глуп и выдает последовательные цифры.
Для чуть менее глупой случайности попробуйте вместо этого что-нибудь вроде этого:
А для истинной (криптографически безопасной) случайности используйте
RANDOM_BYTES()
вместоRAND()
(но тогда я бы подумал о перемещении этой логики на уровень приложения).источник
9
в вашем кодеSELECT LEFT(UUID(), 9);
, всегда-
в конце сгенерированной строки находится девятый символ. Это постоянно. Зачем?SELECT LEFT(REPLACE(UUID(), '-', ''), 16);
Как насчет вычисления MD5 (или другого) хэша последовательных целых чисел, а затем взятия первых 8 символов.
т.е.
и т.п.
предостережение: я понятия не имею, сколько вы можете выделить до столкновения (но это будет известное и постоянное значение).
edit: Теперь это старый ответ, но я снова увидел его со временем, поэтому из наблюдения ...
Вероятность выпадения всех чисел = 2,35%
Вероятность появления всех букв = 0,05%
Первая коллизия, когда MD5 (82945) = "7b763dcb ..." (тот же результат, что и MD5 (25302))
источник
Создать случайную строку
Вот функция MySQL для создания случайной строки заданной длины.
Использование
SELECT RANDSTRING(8)
для возврата строки из 8 символов.Вы можете настроить
@allowedChars
.Уникальность не гарантируется - как вы увидите в комментариях к другим решениям, это просто невозможно. Вместо этого вам нужно будет сгенерировать строку, проверить, используется ли она уже, и повторить попытку, если это так.
Проверьте, не используется ли уже случайная строка
Если мы хотим, чтобы код проверки столкновений не попадал в приложение, мы можем создать триггер:
источник
Вот один из способов использования буквенно-цифровых символов в качестве допустимых символов:
Обратите внимание, что нет гарантии уникальности. Вам нужно будет проверить это отдельно.
источник
Вот еще один метод создания случайной строки:
SELECT SUBSTRING(MD5(RAND()) FROM 1 FOR 8) AS myrandomstring
источник
Вы можете использовать MySQL функции rand () и char () :
источник
Вы можете создать случайную буквенно-цифровую строку с помощью:
Вы можете использовать его в
BEFORE INSERT
триггере и проверять наличие дубликата в цикле while:Теперь просто вставьте свои данные, например
И триггер сгенерирует значение для
plate
столбца.( демонстрация sqlfiddle )
Это работает таким образом, если столбец допускает NULL. Если вы хотите, чтобы оно было НЕ NULL, вам нужно будет определить значение по умолчанию
Вы также можете использовать любой другой алгоритм генерации случайной строки в триггере, если буквенно-цифровые символы в верхнем регистре вам не подходят. Но триггер позаботится об уникальности.
источник
pow(36,8)-1
- это числовое представлениеZZZZZZZZ
. Таким образом, мы генерируем случайное целое число между0
и '36 ^ 8-1' (от0
до2821109907455
) и преобразуем его в буквенно-цифровую строку между0
иZZZZZZZZ
unsingconv()
. lapad () заполнит строку нулями, пока она не станет длиной 8.conv()
поддерживает только основание до 36 (10 цифр + 26 заглавных букв). Если вы хотите использовать строчные буквы, вам понадобится другой способ преобразования числа в строку.Для генерации случайной строки вы можете использовать:
SUBSTRING(MD5(RAND()) FROM 1 FOR 8)
Вы получаете что-то подобное:
353E50CC
источник
Для строки, состоящей из 8 случайных чисел и прописных и строчных букв, это мое решение:
Объясняется изнутри:
RAND
генерирует случайное число от 0 до 1MD5
вычисляет сумму MD5 (1), 32 символа от af и 0-9UNHEX
переводит (2) в 16 байтов со значениями от 00 до FFTO_BASE64
кодирует (3) как base64, 22 символа от az и AZ и 0-9 плюс "/" и "+", за которыми следуют два "="REPLACE
s удаляют символы "/", "+" и "=" из (4)LEFT
берет первые 8 символов из (5), замените 8 на что-то другое, если вам нужно больше или меньше символов в вашей случайной строкеLPAD
вставляет нули в начало (6), если оно меньше 8 символов; опять же, при необходимости измените 8 на другоеисточник
Я использую данные из другого столбца для создания «хеша» или уникальной строки
источник
8 букв алфавита - все заглавные:
источник
Если у вас нет идентификатора или начального числа, например его для списка значений во вставке:
источник
Простое и эффективное решение для получения случайной строки из 10 символов с прописными и строчными буквами и цифрами:
источник
Если вас устраивают «случайные», но полностью предсказуемые номерные знаки, вы можете использовать регистр сдвига с линейной обратной связью, чтобы выбрать следующий номерной знак - он гарантированно пройдется по каждому номеру перед повторением. Однако без сложной математики вы не сможете пройти через каждую 8-символьную буквенно-цифровую строку (вы получите 2 ^ 41 из 36 ^ 8 (78%) возможных табличек). Чтобы это лучше заполняло ваше пространство, вы можете исключить букву из табличек (возможно, O), что даст вам 97%.
источник
Принимая во внимание общее количество символов, которые вам требуются, у вас будет очень небольшая вероятность создания двух точно таких же номерных знаков. Таким образом, вам, вероятно, удастся создать числа в LUA.
У вас есть 36 ^ 8 различных уникальных номерных знаков (2 821 109 907 456, это много), даже если у вас уже был миллион номерных знаков, у вас был бы очень небольшой шанс создать тот, который у вас уже есть, около 0,000035%
Конечно, все зависит от того, сколько номерных знаков вы в итоге создадите.
источник
Эта функция генерирует случайную строку на основе вашей длины ввода и допустимых символов, например:
код функции:
Этот код основан на функции перемешивания строки, отправляемой Россом Смитом II.
источник
Чтобы создать случайный 10-значный буквенно-цифровой символ, исключая похожие символы 01oOlI:
Это именно то, что мне нужно для создания кода ваучера . Непонятные символы удалены, чтобы уменьшить количество ошибок при вводе их в форму кода ваучера.
Надеюсь, что это кому-то поможет, основываясь на блестящем ответе Яна Улига .
Пожалуйста, посмотрите ответ Яна, чтобы узнать, как работает этот код.
источник
Используйте эту хранимую процедуру и используйте ее каждый раз, как
источник
Простой способ сгенерировать уникальный номер
источник
Создать ключ из 8 символов
источник
Я искал что-то подобное и решил создать свою собственную версию, в которой вы также можете указать другое семя, если хотите (список символов) в качестве параметра:
Может использоваться как:
Которая будет использовать встроенное семя из прописных и строчных символов + цифры. NULL также будет значением вместо ''.
Но можно указать собственное семя при вызове:
источник