Ich arbeite an einem Spiel, bei dem es irgendwann um Fahrzeuge geht. Ich habe eine MySQL-Tabelle mit dem Namen "Fahrzeuge", die die Daten zu den Fahrzeugen enthält, einschließlich der Spalte "Kennzeichen", in dem die Kennzeichen für die Fahrzeuge gespeichert sind.
Jetzt kommt der Teil, mit dem ich Probleme habe. Ich muss ein unbenutztes Nummernschild finden, bevor ich ein neues Fahrzeug erstelle - es sollte eine alphanumerische 8-stellige Zufallszeichenfolge sein. Um dies zu erreichen, verwendete ich eine while-Schleife in Lua, der Sprache, in der ich programmiere, um Zeichenfolgen zu generieren und die Datenbank abzufragen, um festzustellen, ob sie verwendet wird. Mit zunehmender Anzahl von Fahrzeugen erwarte ich jedoch, dass dies noch ineffizienter wird, als es derzeit der Fall ist. Aus diesem Grund habe ich beschlossen, dieses Problem mithilfe einer MySQL-Abfrage zu lösen.
Die Abfrage, die ich benötige, sollte einfach eine 8-stellige alphanumerische Zeichenfolge generieren, die noch nicht in der Tabelle enthalten ist. Ich habe wieder über den Generate & Check-Loop-Ansatz nachgedacht, aber ich beschränke diese Frage nicht auf den Fall, dass es einen effizienteren gibt. Ich konnte Zeichenfolgen generieren, indem ich eine Zeichenfolge definierte, die alle zulässigen Zeichen enthielt, und sie nach dem Zufallsprinzip unterzeichnete, und nicht mehr.
Jede Hilfe wird geschätzt.
Antworten:
Dieses Problem besteht aus zwei sehr unterschiedlichen Unterproblemen:
Während Zufälligkeit ziemlich leicht erreicht werden kann, ist die Eindeutigkeit ohne eine Wiederholungsschleife nicht. Dies bringt uns dazu, uns zuerst auf die Einzigartigkeit zu konzentrieren. Nicht zufällige Eindeutigkeit kann trivial mit erreicht werden
AUTO_INCREMENT
. Die Verwendung einer Eindeutigkeit bewahrenden, pseudozufälligen Transformation wäre also in Ordnung:RAND(N)
selbst!Eine Folge von Zufallszahlen, die von demselben Startwert erstellt wurden, ist garantiert
INT32
Also verwenden wir den Ansatz von @ AndreyVolk oder @ GordonLinoff, aber mit einem Startwert
RAND
:zB Assumin
id
ist eineAUTO_INCREMENT
Spalte:quelle
RAND(LAST_INSERT_ID()); UPDATE vehicles (...) , rand()*36+1, (...)
(oder es gibt 8-mal das gleiche Zeichen zurück). Wie können wir sicher sein, dass 8 aufeinanderfolgende Aufruferand()
garantiert eine andere Sequenz zurückgeben, wenn sie mit einem anderen Startwert initialisiert werden?FLOOR()
die zweiten Teilzeichenfolgenparameter hinzufügen musste :…
substring('ABC … 789', floor(rand(@seed:= … )*36+1), 1),
…
In einigen Fällen versuchte die Teilzeichenfolge, das Zeichen 36.9 auszuwählen, was bei einer Aufrundung auf 37 dazu führte, dass kein Zeichen ausgewählt wurde.floor()
. Diese SQL-Geige zeigt, dass Duplikate für drei Zeichen lange Zeichenfolgen erstellt werden.193844
und775771
Ihren Algorithmus wird die gleiche ZeichenfolgeT82X711
( Demo ) generiert .Wie ich in meinem Kommentar sagte, würde ich mich nicht um die Wahrscheinlichkeit einer Kollision kümmern. Generieren Sie einfach eine zufällige Zeichenfolge und prüfen Sie, ob sie vorhanden ist. Wenn dies der Fall ist, versuchen Sie es erneut und Sie sollten es nicht mehr als ein paar Mal tun müssen, es sei denn, Sie haben bereits eine große Anzahl von Platten zugewiesen.
Eine weitere Lösung zum Generieren einer 8 Zeichen langen Pseudozufallszeichenfolge in reinem (My) SQL:
Sie können Folgendes versuchen (Pseudocode):
Da dieser Beitrag ein unerwartetes Maß an Aufmerksamkeit erhalten hat, möchte ich den Kommentar von ADTC hervorheben : Der obige Code ist ziemlich dumm und erzeugt fortlaufende Ziffern.
Versuchen Sie für etwas weniger dumme Zufälligkeit stattdessen Folgendes:
Und für echte (kryptografisch sichere) Zufälligkeit verwenden Sie
RANDOM_BYTES()
eher alsRAND()
(aber dann würde ich in Betracht ziehen, diese Logik auf die Anwendungsschicht zu verschieben).quelle
9
in Ihrem Code verwendeSELECT LEFT(UUID(), 9);
, steht-
am Ende der generierten Zeichenfolge immer das neunte Zeichen. Es ist konstant. Warum?SELECT LEFT(REPLACE(UUID(), '-', ''), 16);
Was ist mit der Berechnung des MD5 (oder eines anderen) Hashs von sequentiellen Ganzzahlen und der Verwendung der ersten 8 Zeichen?
dh
etc.
Vorbehalt: Ich habe keine Ahnung, wie viele Sie vor einer Kollision zuweisen könnten (aber es wäre ein bekannter und konstanter Wert).
edit: Dies ist jetzt eine alte Antwort, aber ich habe sie mit der Zeit wieder gesehen, also aus der Beobachtung ...
Chance aller Zahlen = 2,35%
Chance aller Buchstaben = 0,05%
Erste Kollision bei MD5 (82945) = "7b763dcb ..." (gleiches Ergebnis wie MD5 (25302))
quelle
Erstellen Sie eine zufällige Zeichenfolge
Hier ist eine MySQL-Funktion zum Erstellen einer zufälligen Zeichenfolge mit einer bestimmten Länge.
Verwendung
SELECT RANDSTRING(8)
zur Rückgabe einer 8-stelligen Zeichenfolge.Sie können die anpassen
@allowedChars
.Die Eindeutigkeit kann nicht garantiert werden - wie Sie in den Kommentaren zu anderen Lösungen sehen werden, ist dies einfach nicht möglich. Stattdessen müssen Sie eine Zeichenfolge generieren, prüfen, ob sie bereits verwendet wird, und es erneut versuchen, falls dies der Fall ist.
Überprüfen Sie, ob die zufällige Zeichenfolge bereits verwendet wird
Wenn wir den Code für die Kollisionsprüfung aus der App heraushalten möchten, können wir einen Auslöser erstellen:
quelle
Hier ist eine Möglichkeit, alphanumerische Zeichen als gültige Zeichen zu verwenden:
Beachten Sie, dass keine Garantie für die Eindeutigkeit besteht. Sie müssen dies separat prüfen.
quelle
Hier ist eine andere Methode zum Generieren einer zufälligen Zeichenfolge:
SELECT SUBSTRING(MD5(RAND()) FROM 1 FOR 8) AS myrandomstring
quelle
Sie können die Funktionen rand () und char () von MySQL verwenden :
quelle
Sie können eine zufällige alphanumerische Zeichenfolge generieren mit:
Sie können es in einem
BEFORE INSERT
Trigger verwenden und in einer while-Schleife nach einem Duplikat suchen:Jetzt fügen Sie einfach Ihre Daten wie ein
Und der Trigger generiert einen Wert für die
plate
Spalte.( sqlfiddle Demo )
Das funktioniert so, wenn die Spalte NULL zulässt. Wenn Sie möchten, dass es NICHT NULL ist, müssen Sie einen Standardwert definieren
Sie können auch einen anderen Algorithmus zur Generierung zufälliger Zeichenfolgen im Trigger verwenden, wenn alphanumerische Großbuchstaben nicht Ihren Wünschen entsprechen. Der Auslöser sorgt jedoch für die Einzigartigkeit.
quelle
pow(36,8)-1
ist die numerische Darstellung vonZZZZZZZZ
. Also generieren wir eine zufällige Ganzzahl zwischen0
und '36 ^ 8-1 '(von0
bis2821109907455
) und konvertieren sie in eine alphanumerische Zeichenfolge zwischen0
undZZZZZZZZ
unsingconv()
. lapad () füllt den String mit Nullen, bis er eine Länge von 8 hat.conv()
unterstützt nur eine Basis bis zu 36 (10 Ziffern + 26 Großbuchstaben). Wenn Sie Kleinbuchstaben einfügen möchten, benötigen Sie eine andere Möglichkeit, eine Zahl in eine Zeichenfolge umzuwandeln.Zum Generieren einer zufälligen Zeichenfolge können Sie Folgendes verwenden:
SUBSTRING(MD5(RAND()) FROM 1 FOR 8)
Sie erhalten so etwas:
353E50CC
quelle
Für einen String, der aus 8 Zufallszahlen und Groß- und Kleinbuchstaben besteht, ist dies meine Lösung:
Von innen nach außen erklärt:
RAND
erzeugt eine Zufallszahl zwischen 0 und 1MD5
berechnet die MD5-Summe von (1), 32 Zeichen aus af und 0-9UNHEX
übersetzt (2) in 16 Bytes mit Werten von 00 bis FFTO_BASE64
codiert (3) als base64, 22 Zeichen von az und AZ und 0-9 plus "/" und "+", gefolgt von zwei "="REPLACE
s entfernen die Zeichen "/", "+" und "=" aus (4).LEFT
Nimmt die ersten 8 Zeichen aus (5) und ändert 8 in etwas anderes, wenn Sie mehr oder weniger Zeichen in Ihrer zufälligen Zeichenfolge benötigenLPAD
fügt am Anfang von (6) Nullen ein, wenn es weniger als 8 Zeichen lang ist; Ändern Sie bei Bedarf erneut 8 in etwas anderesquelle
I Verwenden Sie Daten aus einer anderen Spalte, um einen "Hash" oder eine eindeutige Zeichenfolge zu generieren
quelle
8 Buchstaben aus dem Alphabet - Alle Großbuchstaben:
quelle
Wenn Sie keine ID oder keinen Startwert haben, wie dies für eine Werteliste beim Einfügen gilt:
quelle
Einfache und effiziente Lösung, um eine zufällige Zeichenfolge mit 10 Zeichen mit Groß- und Kleinbuchstaben und Ziffern zu erhalten:
quelle
Wenn Sie mit "zufälligen", aber vollständig vorhersehbaren Kennzeichen einverstanden sind, können Sie ein Schieberegister mit linearer Rückkopplung verwenden , um die nächste Kennzeichen-Nummer auszuwählen. Es wird garantiert, dass alle Nummern vor dem Wiederholen durchlaufen werden. Ohne eine komplexe Mathematik können Sie jedoch nicht jede 8-stellige alphanumerische Zeichenfolge durchgehen (Sie erhalten 2 ^ 41 von den 36 ^ 8 (78%) möglichen Platten). Damit dies Ihren Raum besser ausfüllt, können Sie einen Buchstaben von den Tafeln ausschließen (möglicherweise O), wodurch Sie 97% erhalten.
quelle
Wenn Sie die Gesamtzahl der benötigten Zeichen berücksichtigen, haben Sie nur eine sehr geringe Chance, zwei genau ähnliche Nummernschilder zu generieren. So könnten Sie wahrscheinlich mit der Generierung der Zahlen in LUA davonkommen.
Sie haben 36 ^ 8 verschiedene eindeutige Nummernschilder (2.821.109.907.456, das ist eine Menge), selbst wenn Sie bereits eine Million Nummernschilder hatten, hätten Sie eine sehr geringe Chance, eines zu generieren, das Sie bereits haben, etwa 0,000035%
Natürlich hängt alles davon ab, wie viele Nummernschilder Sie am Ende erstellen werden.
quelle
Diese Funktion generiert eine zufällige Zeichenfolge basierend auf Ihrer Eingabelänge und zulässigen Zeichen wie folgt:
Funktionscode:
Dieser Code basiert auf der von "Ross Smith II" gesendeten Shuffle-String-Funktion.
quelle
So erstellen Sie eine zufällige 10-stellige alphanumerische Zahl ohne gleichartige Zeichen 01oOlI:
Genau das brauchte ich, um einen Gutscheincode zu erstellen . Verwirrende Zeichen werden entfernt, um Fehler beim Eingeben in ein Gutscheincodeformular zu reduzieren.
Hoffe, dass dies jemandem hilft, basierend auf Jan Uhligs brillanter Antwort .
In der Antwort von Jan finden Sie eine Aufschlüsselung der Funktionsweise dieses Codes.
quelle
Verwenden Sie diese gespeicherte Prozedur und verwenden Sie sie jedes Mal wie
quelle
Ein einfacher Weg, um eine eindeutige Nummer zu generieren
quelle
Generieren Sie einen 8-Zeichen-Schlüssel
quelle
Ich suchte nach etwas Ähnlichem und entschied mich für eine eigene Version, in der Sie bei Bedarf auch einen anderen Startwert (Liste der Zeichen) als Parameter angeben können:
Kann verwendet werden als:
Welches würde den eingebauten Startwert von Groß- und Kleinbuchstaben + Ziffern verwenden. NULL wäre auch Wert anstelle von ''.
Man könnte aber beim Aufrufen einen benutzerdefinierten Startwert angeben:
quelle