Estou trabalhando em um jogo que envolve veículos em algum momento. Eu tenho uma tabela MySQL chamada "veículos" contendo os dados sobre os veículos, incluindo a coluna "placa" que armazena as placas dos veículos.
Agora vem a parte com a qual estou tendo problemas. Preciso encontrar uma placa de licença não utilizada antes de criar um novo veículo - deve ser uma string alfanumérica aleatória de 8 caracteres. Como consegui isso, usei um loop while em Lua, que é a linguagem em que estou programando, para gerar strings e consultar o banco de dados para ver se ele é usado. No entanto, conforme o número de veículos aumenta, espero que isso se torne ainda mais ineficiente do que é agora. Portanto, decidi tentar resolver esse problema usando uma consulta MySQL.
A consulta de que preciso deve simplesmente gerar uma string alfanumérica de 8 caracteres que ainda não está na tabela. Pensei na abordagem do loop de geração e verificação novamente, mas não estou limitando esta pergunta apenas no caso de haver uma mais eficiente. Consegui gerar strings definindo uma string contendo todos os caracteres permitidos e criando substrings aleatoriamente, e nada mais.
Qualquer ajuda é apreciada.
Respostas:
Este problema consiste em dois subproblemas muito diferentes:
Embora a aleatoriedade seja facilmente alcançada, a exclusividade sem um loop de repetição não é. Isso nos leva a nos concentrarmos primeiro na singularidade. A exclusividade não aleatória pode ser alcançada trivialmente com
AUTO_INCREMENT
. Portanto, usar uma transformação pseudo-aleatória que preserva a exclusividade seria bom:RAND(N)
ele mesmo!Uma sequência de números aleatórios criados pela mesma semente tem a garantia de ser
INT32
Portanto, usamos a abordagem de @ AndreyVolk ou @GordonLinoff, mas com uma semente
RAND
:por exemplo, Assumin
id
é umaAUTO_INCREMENT
coluna:fonte
RAND(LAST_INSERT_ID()); UPDATE vehicles (...) , rand()*36+1, (...)
(ou então ele retorna 8 vezes o mesmo caractere). Como podemos ter certeza de que 8 chamadas sucessivas pararand()
têm garantia de retornar uma sequência diferente se inicializadas com uma semente diferente?FLOOR()
os parâmetros da segunda substring:…
substring('ABC … 789', floor(rand(@seed:= … )*36+1), 1),
…
Em algumas ocasiões, a substring estava tentando escolher o caractere 36,9, que quando arredondado para 37, resultaria em nenhum caractere sendo escolhido.floor()
. Este sqlfiddle mostra que duplicatas são criadas para strings de três caracteres.193844
e775771
seu algoritmo irá gerar a mesma stringT82X711
( demo ).Como afirmei em meu comentário, não me incomodaria com a probabilidade de colisão. Apenas gere uma string aleatória e verifique se ela existe. Se isso acontecer, tente novamente e você não precisará fazer isso mais do que algumas vezes, a menos que já tenha um grande número de pratos atribuídos.
Outra solução para gerar uma string pseudoaleatória de 8 caracteres em SQL puro (My):
Você pode tentar o seguinte (pseudocódigo):
Uma vez que esta postagem recebeu um nível inesperado de atenção, deixe-me destacar o comentário do ADTC : o trecho de código acima é bastante burro e produz dígitos sequenciais.
Para uma aleatoriedade um pouco menos estúpida, tente algo assim:
E para a verdadeira aleatoriedade (criptograficamente segura), use em
RANDOM_BYTES()
vez deRAND()
(mas então eu consideraria mover essa lógica para a camada de aplicativo).fonte
9
em seu códigoSELECT LEFT(UUID(), 9);
, sempre há-
no final da string gerada como o nono caractere. É constante. Por quê?SELECT LEFT(REPLACE(UUID(), '-', ''), 16);
Que tal calcular o hash MD5 (ou outro) de inteiros sequenciais e, em seguida, pegar os primeiros 8 caracteres.
ie
etc.
advertência: não tenho ideia de quantos você poderia alocar antes de uma colisão (mas seria um valor conhecido e constante).
editar: Esta é agora uma resposta antiga, mas eu a vi novamente com o tempo em minhas mãos, então, pela observação ...
Chance de todos os números = 2,35%
Chance de todas as letras = 0,05%
Primeira colisão quando MD5 (82945) = "7b763dcb ..." (mesmo resultado que MD5 (25302))
fonte
Crie uma string aleatória
Aqui está uma função MySQL para criar uma string aleatória de um determinado comprimento.
Uso
SELECT RANDSTRING(8)
para retornar uma string de 8 caracteres.Você pode personalizar o
@allowedChars
.A exclusividade não é garantida - como você verá nos comentários de outras soluções, isso simplesmente não é possível. Em vez disso, você precisará gerar uma string, verificar se já está em uso e tentar novamente se estiver.
Verifique se a string aleatória já está em uso
Se quisermos manter o código de verificação de colisão fora do aplicativo, podemos criar um gatilho:
fonte
Aqui está uma maneira, usando alfanuméricos como caracteres válidos:
Observe que não há garantia de exclusividade. Você terá que verificar isso separadamente.
fonte
Aqui está outro método para gerar uma string aleatória:
SELECT SUBSTRING(MD5(RAND()) FROM 1 FOR 8) AS myrandomstring
fonte
Você pode usar as funções rand () e char () do MySQL :
fonte
Você pode gerar uma string alfanumérica aleatória com:
Você pode usá-lo em um
BEFORE INSERT
gatilho e verificar se há uma duplicata em um loop while:Agora basta inserir seus dados como
E o gatilho irá gerar um valor para a
plate
coluna.( demonstração sqlfiddle )
Isso funciona dessa maneira se a coluna permitir NULLs. Se você quiser que seja NOT NULL, você precisará definir um valor padrão
Você também pode usar qualquer outro algoritmo de geração de string aleatório no acionador se alfanuméricos maiúsculos não forem o que você deseja. Mas o gatilho cuidará da exclusividade.
fonte
pow(36,8)-1
é a representação numérica deZZZZZZZZ
. Portanto, geramos um número inteiro aleatório entre0
e '36 ^ 8-1 '(de0
a2821109907455
) e o convertemos em uma string alfanumérica entre0
eZZZZZZZZ
unsingconv()
. lapad () preencherá a string com zeros até atingir o comprimento de 8.conv()
suporta apenas uma base de até 36 (10 dígitos + 26 letras maiúsculas). Se você quiser incluir letras minúsculas, precisará de outra maneira de converter um número em uma string.Para gerar string aleatória, você pode usar:
SUBSTRING(MD5(RAND()) FROM 1 FOR 8)
Você recebe algo assim:
353E50CC
fonte
Para uma String que consiste em 8 números aleatórios e letras maiúsculas e minúsculas, esta é a minha solução:
Explicado de dentro para fora:
RAND
gera um número aleatório entre 0 e 1MD5
calcula a soma MD5 de (1), 32 caracteres de af e 0-9UNHEX
traduz (2) em 16 bytes com valores de 00 a FFTO_BASE64
codifica (3) como base64, 22 caracteres de az e AZ e 0-9 mais "/" e "+", seguido por dois "="REPLACE
s removem os caracteres "/", "+" e "=" de (4)LEFT
pega os primeiros 8 caracteres de (5), mude 8 para outro se precisar de mais ou menos caracteres em sua string aleatóriaLPAD
insere zeros no início de (6) se tiver menos de 8 caracteres; novamente, mude 8 para algo diferente, se necessáriofonte
I Use dados de outra coluna para gerar um "hash" ou string única
fonte
8 letras do alfabeto - todas maiúsculas:
fonte
Se você não tem um id ou seed, como é para uma lista de valores no insert:
fonte
Solução simples e eficiente para obter uma string aleatória de 10 caracteres com letras maiúsculas e minúsculas e dígitos:
fonte
Se você concorda com placas "aleatórias", mas totalmente previsíveis, você pode usar um registrador de deslocamento de feedback linear para escolher o próximo número de placa - é garantido que todos os números sejam passados antes de repetir. No entanto, sem alguma matemática complexa, você não será capaz de passar por cada string alfanumérica de 8 caracteres (você obterá 2 ^ 41 dos 36 ^ 8 (78%) placas possíveis). Para fazer isso preencher melhor o seu espaço, você pode excluir uma letra das placas (talvez O), dando a você 97%.
fonte
Levando em conta o número total de caracteres que você precisa, você teria uma chance muito pequena de gerar duas placas de matrícula exatamente semelhantes. Portanto, você provavelmente conseguirá gerar os números em LUA.
Você tem 36 ^ 8 placas de número exclusivas diferentes (2.821.109.907.456, isso é muito), mesmo se você já tivesse um milhão de placas de número, você teria uma chance muito pequena de gerar uma que já tem, cerca de 0,000035%
Claro, tudo depende de quantas placas numéricas você acabará criando.
fonte
Esta função gera uma string aleatória com base no comprimento de entrada e caracteres permitidos como este:
código de função:
Este código é baseado na função shuffle string enviada por "Ross Smith II"
fonte
Para criar um alfanumérico aleatório de 10 dígitos , excluindo caracteres semelhantes 01oOlI:
Isso é exatamente o que eu precisava para criar um código de voucher . Caracteres confusos são removidos para reduzir erros ao digitá-los em um formulário de código de voucher.
Espera que isso ajude alguém, com base na resposta brilhante de Jan Uhlig .
Consulte a resposta de Jan para uma análise de como esse código funciona.
fonte
Use este procedimento armazenado e use-o sempre como
fonte
Uma maneira fácil de gerar um número único
fonte
Gerar chave de 8 caracteres
fonte
Eu estava procurando por algo semelhante e decidi fazer minha própria versão onde você também pode especificar uma semente diferente se quiser (lista de personagens) como parâmetro:
Pode ser usado como:
Que usaria a semente embutida de caracteres maiúsculos e minúsculos + dígitos. NULL também seria um valor em vez de ''.
Mas pode-se especificar uma semente personalizada ao chamar:
fonte