Estoy trabajando en un juego que involucra vehículos en algún momento. Tengo una tabla de MySQL llamada "vehículos" que contiene los datos sobre los vehículos, incluida la columna "placa" que almacena las placas de los vehículos.
Ahora aquí viene la parte con la que estoy teniendo problemas. Necesito encontrar una matrícula sin usar antes de crear un nuevo vehículo; debe ser una cadena aleatoria alfanumérica de 8 caracteres. Cómo logré esto fue usando un bucle while en Lua, que es el lenguaje en el que estoy programando, para generar cadenas y consultar la base de datos para ver si se usa. Sin embargo, a medida que aumenta el número de vehículos, espero que esto se vuelva aún más ineficiente que en este momento. Por lo tanto, decidí intentar resolver este problema utilizando una consulta MySQL.
La consulta que necesito debería simplemente generar una cadena alfanumérica de 8 caracteres que aún no está en la tabla. Pensé en el enfoque de generar y verificar bucle nuevamente, pero no estoy limitando esta pregunta a eso en caso de que haya una más eficiente. He podido generar cadenas definiendo una cadena que contiene todos los caracteres permitidos y subcadenando aleatoriamente, y nada más.
Se agradece cualquier ayuda.
Respuestas:
Este problema consta de dos subproblemas muy diferentes:
Si bien la aleatoriedad se logra con bastante facilidad, la singularidad sin un bucle de reintento no lo es. Esto nos lleva a concentrarnos primero en la singularidad. La unicidad no aleatoria se puede lograr trivialmente con
AUTO_INCREMENT
. Entonces, usar una transformación pseudoaleatoria que preserve la singularidad estaría bien:RAND(N)
¡sí mismo!Se garantiza que una secuencia de números aleatorios creada por la misma semilla
INT32
Entonces usamos el enfoque de @ AndreyVolk o @ GordonLinoff, pero con un sembrado
RAND
:por ejemplo, Assumin
id
es unaAUTO_INCREMENT
columna:fuente
RAND(LAST_INSERT_ID()); UPDATE vehicles (...) , rand()*36+1, (...)
(o de lo contrario devuelve 8 veces el mismo carácter). ¿Cómo podemos estar seguros de que se garantiza que 8 llamadas sucesivasrand()
devuelvan una secuencia diferente si se inicializan con una semilla diferente?FLOOR()
alrededor de los parámetros de la segunda subcadena:…
substring('ABC … 789', floor(rand(@seed:= … )*36+1), 1),
…
en algunas ocasiones, la subcadena estaba tratando de elegir el carácter 36.9, que cuando se redondea a 37, no se elige ningún carácter.floor()
. Este sqlfiddle muestra que los duplicados se crean para cadenas de tres caracteres.193844
y775771
su algoritmo generará la misma cadenaT82X711
( demostración ).Como dije en mi comentario, no me molestaría en la posibilidad de colisión. Simplemente genere una cadena aleatoria y verifique si existe. Si es así, inténtelo de nuevo y no debería necesitar hacerlo más de un par de veces a menos que ya tenga una gran cantidad de placas asignadas.
Otra solución para generar una cadena pseudoaleatoria de 8 caracteres en SQL puro (My):
Puede probar lo siguiente (pseudocódigo):
Dado que esta publicación ha recibido un nivel de atención inesperado, permítanme resaltar el comentario de ADTC : la pieza de código anterior es bastante tonta y produce dígitos secuenciales.
Para una aleatoriedad un poco menos estúpida, intente algo como esto en su lugar:
Y para una verdadera aleatoriedad (criptográficamente segura), use en
RANDOM_BYTES()
lugar deRAND()
(pero luego consideraría mover esta lógica a la capa de aplicación).fuente
9
en su códigoSELECT LEFT(UUID(), 9);
, siempre aparece-
al final de la cadena generada como el noveno carácter. Es constante. ¿Por qué?SELECT LEFT(REPLACE(UUID(), '-', ''), 16);
¿Qué hay de calcular el hash MD5 (u otro) de enteros secuenciales y luego tomar los primeros 8 caracteres?
es decir
etc.
advertencia: no tengo idea de cuántos podría asignar antes de una colisión (pero sería un valor conocido y constante).
editar: Esta es ahora una respuesta antigua, pero la vi de nuevo con tiempo en mis manos, así que, desde la observación ...
Probabilidad de todos los números = 2,35%
Probabilidad de todas las letras = 0.05%
Primera colisión cuando MD5 (82945) = "7b763dcb ..." (mismo resultado que MD5 (25302))
fuente
Crea una cadena aleatoria
Aquí hay una función de MySQL para crear una cadena aleatoria de una longitud determinada.
Uso
SELECT RANDSTRING(8)
para devolver una cadena de 8 caracteres.Puede personalizar el
@allowedChars
.La singularidad no está garantizada; como verá en los comentarios de otras soluciones, esto simplemente no es posible. En su lugar, deberá generar una cadena, verificar si ya está en uso y volver a intentarlo si lo está.
Compruebe si la cadena aleatoria ya está en uso
Si queremos mantener el código de verificación de colisiones fuera de la aplicación, podemos crear un disparador:
fuente
Aquí hay una forma, usando alfanuméricos como caracteres válidos:
Tenga en cuenta que no hay garantía de unicidad. Tendrá que comprobarlo por separado.
fuente
Aquí hay otro método para generar una cadena aleatoria:
SELECT SUBSTRING(MD5(RAND()) FROM 1 FOR 8) AS myrandomstring
fuente
Puede usar la función rand () y char () de MySQL :
fuente
Puede generar una cadena alfanumérica aleatoria con:
Puede usarlo en un
BEFORE INSERT
disparador y verificar si hay un duplicado en un ciclo while:Ahora solo inserta tus datos como
Y el disparador generará un valor para la
plate
columna.( demostración de sqlfiddle )
Eso funciona de esta manera si la columna permite NULL. Si desea que NO sea NULO, deberá definir un valor predeterminado
También puede usar cualquier otro algoritmo de generación de cadenas aleatorias en el activador si las letras alfanuméricas en mayúsculas no son lo que desea. Pero el disparador se encargará de la singularidad.
fuente
pow(36,8)-1
es la representación numérica deZZZZZZZZ
. Entonces, generamos un número entero aleatorio entre0
y '36 ^ 8-1 '(de0
a2821109907455
) y lo convertimos en una cadena alfanumérica entre0
yZZZZZZZZ
unsingconv()
. lapad () llenará la cadena con ceros hasta que tenga una longitud de 8.conv()
solo admite una base de hasta 36 (10 dígitos + 26 letras mayúsculas). Si desea incluir letras minúsculas, necesitará otra forma de convertir un número en una cadena.Para generar una cadena aleatoria, puede usar:
SUBSTRING(MD5(RAND()) FROM 1 FOR 8)
Recibes algo así:
353E50CC
fuente
Para una cadena que consta de 8 números aleatorios y letras mayúsculas y minúsculas, esta es mi solución:
Explicado de adentro hacia afuera:
RAND
genera un número aleatorio entre 0 y 1MD5
calcula la suma MD5 de (1), 32 caracteres de af y 0-9UNHEX
traduce (2) en 16 bytes con valores de 00 a FFTO_BASE64
codifica (3) como base64, 22 caracteres de az y AZ y 0-9 más "/" y "+", seguidos de dos "="REPLACE
eliminan los caracteres "/", "+" y "=" de (4)LEFT
toma los primeros 8 caracteres de (5), cambie 8 a otra cosa si necesita más o menos caracteres en su cadena aleatoriaLPAD
inserta ceros al principio de (6) si tiene menos de 8 caracteres; de nuevo, cambie 8 a otra cosa si es necesariofuente
Utilizo datos de otra columna para generar un "hash" o una cadena única
fuente
8 letras del alfabeto - Todo en mayúsculas:
fuente
Si no tiene una identificación o semilla, como si fuera una lista de valores en la inserción:
fuente
Solución simple y eficiente para obtener una cadena aleatoria de 10 caracteres con letras mayúsculas y minúsculas y dígitos:
fuente
Si está de acuerdo con las matrículas "aleatorias" pero completamente predecibles, puede usar un registro de desplazamiento de retroalimentación lineal para elegir el siguiente número de matrícula; se garantiza que pasará por todos los números antes de repetir. Sin embargo, sin algunas matemáticas complejas, no podrá pasar por cada cadena alfanumérica de 8 caracteres (obtendrá 2 ^ 41 de las 36 ^ 8 (78%) placas posibles). Para que esto llene mejor su espacio, podría excluir una letra de las placas (tal vez O), lo que le da un 97%.
fuente
Teniendo en cuenta el número total de caracteres que necesita, tendría una probabilidad muy pequeña de generar dos matrículas exactamente similares. Por lo tanto, probablemente podría salirse con la suya generando los números en LUA.
Tiene 36 ^ 8 placas de matrícula únicas diferentes (2.821.109.907.456, eso es mucho), incluso si ya tuviera un millón de placas de matrícula, tendría una posibilidad muy pequeña de generar una que ya tiene, aproximadamente 0.000035%
Por supuesto, todo depende de la cantidad de matrículas que acabes creando.
fuente
Esta función genera una cadena aleatoria basada en la longitud de su entrada y los caracteres permitidos como este:
Código de función:
Este código se basa en la función de secuencia aleatoria que envía "Ross Smith II"
fuente
Para crear un alfanumérico aleatorio de 10 dígitos , excluyendo los caracteres similares 01oOlI:
Esto es exactamente lo que necesitaba para crear un código de cupón. . Los caracteres confusos se eliminan para reducir los errores al escribirlos en un formulario de código de cupón.
Espera que esto ayude a alguien, según la brillante respuesta de Jan Uhlig .
Consulte la respuesta de Jan para obtener un desglose de cómo funciona este código.
fuente
Utilice este procedimiento almacenado y utilícelo siempre como
fuente
Una forma sencilla de generar un número único
fuente
Generar clave de 8 caracteres
fuente
Estaba buscando algo similar y decidí hacer mi propia versión donde también se puede especificar una semilla diferente si se desea (lista de caracteres) como parámetro:
Puede usarse como:
Que usaría la semilla incorporada de caracteres en mayúsculas y minúsculas + dígitos. NULL también sería valor en lugar de ''.
Pero se podría especificar una semilla personalizada al llamar:
fuente