Je travaille sur un jeu qui implique des véhicules à un moment donné. J'ai une table MySQL nommée «véhicules» contenant les données sur les véhicules, y compris la colonne «plaque» qui stocke les plaques d'immatriculation des véhicules.
Maintenant, voici la partie avec laquelle j'ai des problèmes. Je dois trouver une plaque d'immatriculation inutilisée avant de créer un nouveau véhicule - il devrait s'agir d'une chaîne aléatoire alphanumérique de 8 caractères. La façon dont j'ai réalisé cela a été d'utiliser une boucle while dans Lua, qui est le langage dans lequel je programme, pour générer des chaînes et interroger la base de données pour voir si elle est utilisée. Cependant, à mesure que le nombre de véhicules augmente, je m'attends à ce que cela devienne encore plus inefficace qu'il l'est actuellement. Par conséquent, j'ai décidé d'essayer de résoudre ce problème en utilisant une requête MySQL.
La requête dont j'ai besoin doit simplement générer une chaîne alphanumérique de 8 caractères qui n'est pas déjà dans le tableau. J'ai de nouveau pensé à l'approche de la boucle de génération et de vérification, mais je ne me limite pas à cette question au cas où il y en aurait une plus efficace. J'ai pu générer des chaînes en définissant une chaîne contenant tous les caractères autorisés et en la sous-chaînant de manière aléatoire, et rien de plus.
Toute aide est appréciée.
Réponses:
Ce problème se compose de deux sous-problèmes très différents:
Bien que le caractère aléatoire soit assez facile à atteindre, l'unicité sans boucle de relance ne l'est pas. Cela nous amène à nous concentrer d'abord sur l'unicité. L'unicité non aléatoire peut être obtenue de manière triviale avec
AUTO_INCREMENT
. Donc, utiliser une transformation pseudo-aléatoire préservant l'unicité serait bien:RAND(N)
elle - même!Une séquence de nombres aléatoires créée par la même graine est garantie d'être
INT32
Nous utilisons donc @ AndreyVolk ou de @ l'approche de GordonLinoff, mais avec une tête de série
RAND
:Par exemple, Assumin
id
est uneAUTO_INCREMENT
colonne:la source
RAND(LAST_INSERT_ID()); UPDATE vehicles (...) , rand()*36+1, (...)
(sinon elle renvoie 8 fois le même caractère). Comment pouvons-nous être sûrs que 8 appels successifs àrand()
sont garantis de retourner une séquence différente s'ils sont initialisés avec une graine différente?FLOOR()
autour des paramètres de la deuxième sous-chaîne: à…
substring('ABC … 789', floor(rand(@seed:= … )*36+1), 1),
…
certaines occasions, la sous-chaîne essayait de choisir le caractère 36.9, qui, arrondi à 37, n'entraînerait aucun caractère choisi.floor()
. Ce sqlfiddle montre que des doublons sont créés pour des chaînes de trois caractères.193844
et775771
votre algorithme générera la même chaîneT82X711
( démo ).Comme je l'ai dit dans mon commentaire, je ne me soucierais pas de la probabilité de collision. Générez simplement une chaîne aléatoire et vérifiez si elle existe. Si c'est le cas, réessayez et vous ne devriez pas avoir besoin de le faire plus de deux fois à moins que vous n'ayez déjà attribué un grand nombre de plaques.
Une autre solution pour générer une chaîne pseudo-aléatoire de 8 caractères en pure (My) SQL:
Vous pouvez essayer ce qui suit (pseudo-code):
Étant donné que cet article a reçu un niveau d'attention inattendu, permettez-moi de souligner le commentaire de l'ADTC : le morceau de code ci-dessus est assez stupide et produit des chiffres séquentiels.
Pour un hasard un peu moins stupide, essayez plutôt quelque chose comme ceci:
Et pour un vrai hasard (cryptograpiquement sécurisé), utilisez
RANDOM_BYTES()
plutôt queRAND()
(mais j'envisagerais alors de déplacer cette logique vers la couche application).la source
9
dans votre codeSELECT LEFT(UUID(), 9);
, il y a toujours-
à la fin de la chaîne générée comme neuvième caractère. C'est constant. Pourquoi?SELECT LEFT(REPLACE(UUID(), '-', ''), 16);
Qu'en est-il du calcul du hachage MD5 (ou autre) d'entiers séquentiels, puis en prenant les 8 premiers caractères.
c'est à dire
etc.
mise en garde: je n'ai aucune idée du nombre que vous pourriez allouer avant une collision (mais ce serait une valeur connue et constante).
edit: C'est maintenant une vieille réponse, mais je l'ai revu avec le temps sur mes mains, donc, de l'observation ...
Chance de tous les nombres = 2,35%
Chance de toutes les lettres = 0,05%
Première collision lorsque MD5 (82945) = "7b763dcb ..." (même résultat que MD5 (25302))
la source
Créer une chaîne aléatoire
Voici une fonction MySQL pour créer une chaîne aléatoire d'une longueur donnée.
Usage
SELECT RANDSTRING(8)
pour renvoyer une chaîne de 8 caractères.Vous pouvez personnaliser le
@allowedChars
.L'unicité n'est pas garantie - comme vous le verrez dans les commentaires sur d'autres solutions, ce n'est tout simplement pas possible. Au lieu de cela, vous devrez générer une chaîne, vérifier si elle est déjà utilisée et réessayer si elle l'est.
Vérifiez si la chaîne aléatoire est déjà utilisée
Si nous voulons garder le code de vérification de collision hors de l'application, nous pouvons créer un déclencheur:
la source
Voici une façon d'utiliser les caractères alphanumériques comme caractères valides:
Notez qu'il n'y a aucune garantie d'unicité. Vous devrez vérifier cela séparément.
la source
Voici une autre méthode pour générer une chaîne aléatoire:
SELECT SUBSTRING(MD5(RAND()) FROM 1 FOR 8) AS myrandomstring
la source
Vous pouvez utiliser les fonctions rand () et char () de MySQL :
la source
Vous pouvez générer une chaîne alphanumérique aléatoire avec:
Vous pouvez l'utiliser dans un
BEFORE INSERT
déclencheur et rechercher un doublon dans une boucle while:Maintenant, insérez simplement vos données comme
Et le déclencheur générera une valeur pour le
plate
colonne.( démo sqlfiddle )
Cela fonctionne de cette façon si la colonne autorise les valeurs NULL. Si vous voulez qu'il ne soit PAS NULL, vous devez définir une valeur par défaut
Vous pouvez également utiliser n'importe quel autre algorithme de génération de chaîne aléatoire dans le déclencheur si les alphanumériques majuscules ne sont pas ce que vous voulez. Mais le déclencheur prendra soin de l'unicité.
la source
pow(36,8)-1
est la représentation numérique deZZZZZZZZ
. Nous générons donc un entier aléatoire entre0
et '36 ^ 8-1 '(de0
à2821109907455
) et le convertissons en une chaîne alphanumérique entre0
etZZZZZZZZ
unsingconv()
. lapad () remplira la chaîne de zéros jusqu'à ce qu'elle ait une longueur de 8.conv()
ne prend en charge qu'une base jusqu'à 36 (10 chiffres + 26 lettres majuscules). Si vous souhaitez inclure des lettres minuscules, vous aurez besoin d'un autre moyen de convertir un nombre en chaîne.Pour générer une chaîne aléatoire, vous pouvez utiliser:
SUBSTRING(MD5(RAND()) FROM 1 FOR 8)
Vous recevez comme ça:
353E50CC
la source
Pour une chaîne composée de 8 nombres aléatoires et de lettres majuscules et minuscules, voici ma solution:
Expliqué de l'intérieur:
RAND
génère un nombre aléatoire entre 0 et 1MD5
calcule la somme MD5 de (1), 32 caractères de af et 0-9UNHEX
traduit (2) en 16 octets avec des valeurs de 00 à FFTO_BASE64
encode (3) en base64, 22 caractères de az et AZ et 0-9 plus "/" et "+", suivis de deux "="REPLACE
suppriment les caractères "/", "+" et "=" de (4)LEFT
prend les 8 premiers caractères de (5), remplacez 8 par autre chose si vous avez besoin de plus ou moins de caractères dans votre chaîne aléatoireLPAD
insère des zéros au début de (6) s'il comporte moins de 8 caractères; encore une fois, remplacez 8 par autre chose si nécessairela source
I Utiliser les données d'une autre colonne pour générer un "hachage" ou une chaîne unique
la source
8 lettres de l'alphabet - Tout en majuscules:
la source
Si vous n'avez pas d'identifiant ou de graine, comme c'est pour une liste de valeurs dans insérer:
la source
Solution simple et efficace pour obtenir une chaîne aléatoire de 10 caractères avec des lettres et des chiffres majuscules et minuscules:
la source
Si vous êtes d'accord avec des plaques d'immatriculation «aléatoires» mais entièrement prévisibles, vous pouvez utiliser un registre à décalage à rétroaction linéaire pour choisir le numéro de plaque suivant - il est garanti de parcourir chaque numéro avant de le répéter. Cependant, sans quelques mathématiques complexes, vous ne pourrez pas parcourir chaque chaîne alphanumérique de 8 caractères (vous obtiendrez 2 ^ 41 sur les 36 ^ 8 (78%) plaques possibles). Pour que cela remplisse mieux votre espace, vous pouvez exclure une lettre des plaques (peut-être O), ce qui vous donne 97%.
la source
Compte tenu du nombre total de caractères dont vous avez besoin, vous auriez une très petite chance de générer deux plaques d'immatriculation exactement similaires. Ainsi, vous pourriez probablement vous en sortir avec la génération des nombres dans LUA.
Vous avez 36 ^ 8 plaques d'immatriculation uniques différentes (2,821,109,907,456, c'est beaucoup), même si vous aviez déjà un million de plaques d'immatriculation, vous auriez une très petite chance d'en générer une que vous avez déjà, environ 0,000035%
Bien sûr, tout dépend du nombre de plaques d'immatriculation que vous finirez par créer.
la source
Cette fonction génère une chaîne aléatoire en fonction de la longueur de votre entrée et des caractères autorisés comme ceci:
code de fonction:
Ce code est basé sur la fonction de chaîne aléatoire envoyée par "Ross Smith II"
la source
Pour créer un alphanumérique aléatoire à 10 chiffres , à l'exclusion des caractères sosies 01oOlI:
C'est exactement ce dont j'avais besoin pour créer un code de bon d'achat . Les caractères déroutants sont supprimés pour réduire les erreurs lors de la saisie dans un formulaire de code de bon.
Espère que cela aide quelqu'un, basé sur la réponse brillante de Jan Uhlig .
Veuillez consulter la réponse de Jan pour une description du fonctionnement de ce code.
la source
Utilisez cette procédure stockée et utilisez-la à chaque fois comme
la source
Un moyen simple de générer un numéro unique
la source
Générer une clé de 8 caractères
la source
Je cherchais quelque chose de similaire et j'ai décidé de créer ma propre version où vous pouvez également spécifier une graine différente si vous le souhaitez (liste de caractères) comme paramètre:
Peut être utilisé comme:
Ce qui utiliserait la graine intégrée de caractères majuscules et minuscules + chiffres. NULL serait également une valeur au lieu de «».
Mais on pourrait spécifier une graine personnalisée lors de l'appel:
la source