Generieren einer zufälligen und eindeutigen 8-stelligen Zeichenfolge mit MySQL

109

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.

Funstein
quelle
Wie zufällig müssen diese sein? Wenn jemand ein bestimmtes Nummernschild erhält, ist es wichtig oder nicht, ob er das nächste oder vorherige Nummernschild, das Sie ausgehändigt haben, ausarbeiten kann?
Damien_The_Unbeliever
@YaK Siehe meine Antwort, wie man selbst die winzige Möglichkeit einer Kollision vermeidet
Eugen Rieck

Antworten:

87

Dieses Problem besteht aus zwei sehr unterschiedlichen Unterproblemen:

  • Die Zeichenfolge muss scheinbar zufällig sein
  • Die Zeichenfolge muss eindeutig sein

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:

  • Hash wurde von @paul vorgeschlagen
  • AES-Verschlüsselung passt auch
  • Aber es gibt eine schöne: sich RAND(N)selbst!

Eine Folge von Zufallszahlen, die von demselben Startwert erstellt wurden, ist garantiert

  • reproduzierbar
  • anders für die ersten 8 Iterationen
  • wenn der Samen ein ist INT32

Also verwenden wir den Ansatz von @ AndreyVolk oder @ GordonLinoff, aber mit einem Startwert RAND :

zB Assumin idist eine AUTO_INCREMENTSpalte:

INSERT INTO vehicles VALUES (blah); -- leaving out the number plate
SELECT @lid:=LAST_INSERT_ID();
UPDATE vehicles SET numberplate=concat(
  substring('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', rand(@seed:=round(rand(@lid)*4294967296))*36+1, 1),
  substring('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', rand(@seed:=round(rand(@seed)*4294967296))*36+1, 1),
  substring('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', rand(@seed:=round(rand(@seed)*4294967296))*36+1, 1),
  substring('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', rand(@seed:=round(rand(@seed)*4294967296))*36+1, 1),
  substring('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', rand(@seed:=round(rand(@seed)*4294967296))*36+1, 1),
  substring('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', rand(@seed:=round(rand(@seed)*4294967296))*36+1, 1),
  substring('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', rand(@seed:=round(rand(@seed)*4294967296))*36+1, 1),
  substring('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', rand(@seed)*36+1, 1)
)
WHERE id=@lid;
Eugen Rieck
quelle
Sehr interessanter Ansatz, aber Sie haben es wahrscheinlich gemeint 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 Aufrufe rand()garantiert eine andere Sequenz zurückgeben, wenn sie mit einem anderen Startwert initialisiert werden?
RandomSeed
8
Ich habe mich nur gefragt. Warum verwenden Sie diese Zahlen ..4294967296)) * 36 + 1?
Mick
7
Dies ist ein bisschen alt, aber ich möchte darauf hinweisen, dass ich 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.
Phillip Dodson
4
Sie können eine Zeichenfolge nicht zufällig aufrufen, wenn sie reproduzierbar ist. Und Duplikate sind auch möglich, weil Sie verwenden floor(). Diese SQL-Geige zeigt, dass Duplikate für drei Zeichen lange Zeichenfolgen erstellt werden.
Paul Spiegel
6
@EugenRieck Ich verstehe nicht, wie Sie Ihre Zahlen erhalten ("erste 2 ^ 32 Iterationen"). Aber ich brauche nur ein Beispiel für Duplikate, um dieses Konzept zu widerlegen. Für die IDs 193844und 775771Ihren Algorithmus wird die gleiche Zeichenfolge T82X711( Demo ) generiert .
Paul Spiegel
112

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:

SELECT LEFT(UUID(), 8);

Sie können Folgendes versuchen (Pseudocode):

DO 
    SELECT LEFT(UUID(), 8) INTO @plate;
    INSERT INTO plates (@plate);
WHILE there_is_a_unique_constraint_violation
-- @plate is your newly assigned plate number

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:

SELECT LEFT(MD5(RAND()), 8)

Und für echte (kryptografisch sichere) Zufälligkeit verwenden Sie RANDOM_BYTES()eher als RAND()(aber dann würde ich in Betracht ziehen, diese Logik auf die Anwendungsschicht zu verschieben).

RandomSeed
quelle
Vielen Dank für Ihre Lösung. Ich habe eine Frage zu UUID. Wie viele Chancen es hat, dass die von Ihnen generierte ID mit 8 Zeichen erneut wiederholt wird.
TR-Ahmed
1
@ user3099183 Offiziell "sehr niedrig". 16 ^ 8 sind ungefähr 4 Milliarden mögliche Saiten.
RandomSeed
23
Bitte beachten Sie, dass die ersten 8 Zeichen der UUID nicht zufällig, sondern sequentiell sind, da sie auf dem Zeitstempel basieren.
ADTC
Ich möchte eine 9 Zeichen lange zufällige Zeichenfolge generieren, und wenn ich sie 9in Ihrem Code verwende SELECT LEFT(UUID(), 9);, steht -am Ende der generierten Zeichenfolge immer das neunte Zeichen. Es ist konstant. Warum?
Martin AJ
3
@MartinAJ, weil der String eine UUID ist . Sie können die Bindestriche leicht ersetzen, zBSELECT LEFT(REPLACE(UUID(), '-', ''), 16);
jchook
53

Was ist mit der Berechnung des MD5 (oder eines anderen) Hashs von sequentiellen Ganzzahlen und der Verwendung der ersten 8 Zeichen?

dh

MD5(1) = c4ca4238a0b923820dcc509a6f75849b => c4ca4238
MD5(2) = c81e728d9d4c2f636f067f89cc14862c => c81e728d
MD5(3) = eccbc87e4b5ce2fe28308fd9f2a7baf3 => eccbc87e

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))

paul
quelle
2
Gute Idee, könnte es auf dem Primärschlüssel verwenden. Ich werde dies für zukünftige Projekte berücksichtigen, danke!
Funstein
2
Es besteht die Möglichkeit, dass dies nur mit Zahlen resultieren könnte
Mladen Janjetovic
9
Es ist überhaupt nicht zufällig.
Paul
1
Sie könnten es "zufälliger" machen, wenn Sie anstelle der automatischen inkrementellen ID die Datums- und Uhrzeitangabe verwenden, in der die Einfügung durchgeführt wurde, was ebenfalls eindeutig ist.
Javier La Banca
35

Erstellen Sie eine zufällige Zeichenfolge

Hier ist eine MySQL-Funktion zum Erstellen einer zufälligen Zeichenfolge mit einer bestimmten Länge.

DELIMITER $$

CREATE DEFINER=`root`@`%` FUNCTION `RandString`(length SMALLINT(3)) RETURNS varchar(100) CHARSET utf8
begin
    SET @returnStr = '';
    SET @allowedChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
    SET @i = 0;

    WHILE (@i < length) DO
        SET @returnStr = CONCAT(@returnStr, substring(@allowedChars, FLOOR(RAND() * LENGTH(@allowedChars) + 1), 1));
        SET @i = @i + 1;
    END WHILE;

    RETURN @returnStr;
END

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:

DELIMITER $$

CREATE TRIGGER Vehicle_beforeInsert
  BEFORE INSERT ON `Vehicle`
  FOR EACH ROW
  BEGIN
    SET @vehicleId = 1;
    WHILE (@vehicleId IS NOT NULL) DO 
      SET NEW.plate = RANDSTRING(8);
      SET @vehicleId = (SELECT id FROM `Vehicle` WHERE `plate` = NEW.plate);
    END WHILE;
  END;$$
DELIMITER ;
Paddy Mann
quelle
6
Dies sollte die akzeptierte Antwort sein, klar und auf den Punkt, funktionierte gut für mich, danke @ paddy-mann
Saif
Dies ist die beste Lösung, denke ich. Danke, Mann!
Pronoy999
23

Hier ist eine Möglichkeit, alphanumerische Zeichen als gültige Zeichen zu verwenden:

select concat(substring('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', rand()*36+1, 1),
              substring('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', rand()*36+1, 1),
              substring('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', rand()*36+1, 1),
              substring('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', rand()*36+1, 1),
              substring('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', rand()*36+1, 1),
              substring('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', rand()*36+1, 1),
              substring('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', rand()*36+1, 1),
              substring('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', rand()*36+1, 1)
             ) as LicensePlaceNumber;

Beachten Sie, dass keine Garantie für die Eindeutigkeit besteht. Sie müssen dies separat prüfen.

Gordon Linoff
quelle
7
Verwenden Sie stattdessen floor (rand () * 36 + 1). Andernfalls sind einige Ergebnisse "kurz".
Fraggle
2
es sollte 35 + 1 sein, nicht 36 + 1! Andernfalls erhalten Sie einige Zeichenfolgen mit 8 Zeichen und einige mit 7
BIOHAZARD
23

Hier ist eine andere Methode zum Generieren einer zufälligen Zeichenfolge:

SELECT SUBSTRING(MD5(RAND()) FROM 1 FOR 8) AS myrandomstring

Beingalex
quelle
16

Sie können die Funktionen rand () und char () von MySQL verwenden :

select concat( 
    char(round(rand()*25)+97),
    char(round(rand()*25)+97),
    char(round(rand()*25)+97),
    char(round(rand()*25)+97),
    char(round(rand()*25)+97),
    char(round(rand()*25)+97),
    char(round(rand()*25)+97),
    char(round(rand()*25)+97)
) as name;
Andrey Volk
quelle
14

Sie können eine zufällige alphanumerische Zeichenfolge generieren mit:

lpad(conv(floor(rand()*pow(36,8)), 10, 36), 8, 0);

Sie können es in einem BEFORE INSERTTrigger verwenden und in einer while-Schleife nach einem Duplikat suchen:

CREATE TABLE `vehicles` (
    `plate` CHAR(8) NULL DEFAULT NULL,
    `data` VARCHAR(50) NOT NULL,
    UNIQUE INDEX `plate` (`plate`)
);

DELIMITER //
CREATE TRIGGER `vehicles_before_insert` BEFORE INSERT ON `vehicles`
FOR EACH ROW BEGIN

    declare str_len int default 8;
    declare ready int default 0;
    declare rnd_str text;
    while not ready do
        set rnd_str := lpad(conv(floor(rand()*pow(36,str_len)), 10, 36), str_len, 0);
        if not exists (select * from vehicles where plate = rnd_str) then
            set new.plate = rnd_str;
            set ready := 1;
        end if;
    end while;

END//
DELIMITER ;

Jetzt fügen Sie einfach Ihre Daten wie ein

insert into vehicles(col1, col2) values ('value1', 'value2');

Und der Trigger generiert einen Wert für die plateSpalte.

( 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

`plate` CHAR(8) NOT NULL DEFAULT 'default',

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.

Paul Spiegel
quelle
Tolle! Genau das wollte ich. Ich möchte nur verstehen, wie es in einen String konvertiert wird. Warum gibt es eine Macht, was zu tun ist, um Zahlen hinzuzufügen und so weiter. Trotzdem danke.
Akxe
Mit @Akxe conv () kann eine Zahl in eine alphanumerische Zeichenfolge konvertiert werden. pow(36,8)-1ist die numerische Darstellung von ZZZZZZZZ. Also generieren wir eine zufällige Ganzzahl zwischen 0und '36 ^ 8-1 '(von 0bis 2821109907455) und konvertieren sie in eine alphanumerische Zeichenfolge zwischen 0und ZZZZZZZZunsing conv(). lapad () füllt den String mit Nullen, bis er eine Länge von 8 hat.
Paul Spiegel
Sie, mein Herr, sind ein Genie. Ich stelle mir vor, dass das Hinzufügen von Kleinbuchstaben aufgrund der Nichtkontinuität von Zeichen unmöglich ist. (91-96) Nicht, dass ich es brauche, nur neugierig ...
Akxe
@Akxe 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.
Paul Spiegel
Vorsichtsmaßnahme: funktioniert nicht für str_len> 13. Ab 14 erhalten Sie immer '3W5E11264SGSF'. ;-)
Gerard H. Pille
6

Zum Generieren einer zufälligen Zeichenfolge können Sie Folgendes verwenden:

SUBSTRING(MD5(RAND()) FROM 1 FOR 8)

Sie erhalten so etwas:

353E50CC

Nikita G.
quelle
5

Für einen String, der aus 8 Zufallszahlen und Groß- und Kleinbuchstaben besteht, ist dies meine Lösung:

LPAD(LEFT(REPLACE(REPLACE(REPLACE(TO_BASE64(UNHEX(MD5(RAND()))), "/", ""), "+", ""), "=", ""), 8), 8, 0)

Von innen nach außen erklärt:

  1. RAND erzeugt eine Zufallszahl zwischen 0 und 1
  2. MD5 berechnet die MD5-Summe von (1), 32 Zeichen aus af und 0-9
  3. UNHEX übersetzt (2) in 16 Bytes mit Werten von 00 bis FF
  4. TO_BASE64 codiert (3) als base64, 22 Zeichen von az und AZ und 0-9 plus "/" und "+", gefolgt von zwei "="
  5. Die drei REPLACEs entfernen die Zeichen "/", "+" und "=" aus (4).
  6. 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ötigen
  7. LPADfügt am Anfang von (6) Nullen ein, wenn es weniger als 8 Zeichen lang ist; Ändern Sie bei Bedarf erneut 8 in etwas anderes
Jan Uhlig
quelle
Großartig, genau das, wonach ich gesucht habe, um eine
tokenartige
4

I Verwenden Sie Daten aus einer anderen Spalte, um einen "Hash" oder eine eindeutige Zeichenfolge zu generieren

UPDATE table_name SET column_name = Right( MD5(another_column_with_data), 8 )
Richard Fragiacomo
quelle
4

8 Buchstaben aus dem Alphabet - Alle Großbuchstaben:

UPDATE `tablename` SET `tablename`.`randomstring`= concat(CHAR(FLOOR(65 + (RAND() * 25))),CHAR(FLOOR(65 + (RAND() * 25))),CHAR(FLOOR(65 + (RAND() * 25))),CHAR(FLOOR(65 + (RAND() * 25)))CHAR(FLOOR(65 + (RAND() * 25))),CHAR(FLOOR(65 + (RAND() * 25))),CHAR(FLOOR(65 + (RAND() * 25))),CHAR(FLOOR(65 + (RAND() * 25))));
TV-C-15
quelle
3

Wenn Sie keine ID oder keinen Startwert haben, wie dies für eine Werteliste beim Einfügen gilt:

REPLACE(RAND(), '.', '')
ekerner
quelle
2

Einfache und effiziente Lösung, um eine zufällige Zeichenfolge mit 10 Zeichen mit Groß- und Kleinbuchstaben und Ziffern zu erhalten:

select substring(base64_encode(md5(rand())) from 1+rand()*4 for 10);
Antares
quelle
1

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
1

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.

Lawrence Andrews
quelle
Es stimmt, ich mache es im eigentlichen Spiel anstelle von SQL weiter. Vielen Dank.
Funstein
1

Diese Funktion generiert eine zufällige Zeichenfolge basierend auf Ihrer Eingabelänge und zulässigen Zeichen wie folgt:

SELECT str_rand(8, '23456789abcdefghijkmnpqrstuvwxyz');

Funktionscode:

DROP FUNCTION IF EXISTS str_rand;

DELIMITER //

CREATE FUNCTION str_rand(
    u_count INT UNSIGNED,
    v_chars TEXT
)
RETURNS TEXT
NOT DETERMINISTIC
NO SQL
SQL SECURITY INVOKER
COMMENT ''
BEGIN
    DECLARE v_retval TEXT DEFAULT '';
    DECLARE u_pos    INT UNSIGNED;
    DECLARE u        INT UNSIGNED;

    SET u = LENGTH(v_chars);
    WHILE u_count > 0
    DO
      SET u_pos = 1 + FLOOR(RAND() * u);
      SET v_retval = CONCAT(v_retval, MID(v_chars, u_pos, 1));
      SET u_count = u_count - 1;
    END WHILE;

    RETURN v_retval;
END;
//
DELIMITER ;

Dieser Code basiert auf der von "Ross Smith II" gesendeten Shuffle-String-Funktion.

Mahoor13
quelle
Diese Funktion generiert keinen zufälligen eindeutigen Wert.
Faisal
1

So erstellen Sie eine zufällige 10-stellige alphanumerische Zahl ohne gleichartige Zeichen 01oOlI:

LPAD(LEFT(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(TO_BASE64(UNHEX(MD5(RAND()))), "/", ""), "+", ""), "=", ""), "O", ""), "l", ""), "I", ""), "1", ""), "0", ""), "o", ""), 10), 10, 0)

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.

Paul Harris
quelle
0
DELIMITER $$

USE `temp` $$

DROP PROCEDURE IF EXISTS `GenerateUniqueValue`$$

CREATE PROCEDURE `GenerateUniqueValue`(IN tableName VARCHAR(255),IN columnName VARCHAR(255)) 
BEGIN
    DECLARE uniqueValue VARCHAR(8) DEFAULT "";
    WHILE LENGTH(uniqueValue) = 0 DO
        SELECT CONCAT(SUBSTRING('ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789', RAND()*34+1, 1),
                SUBSTRING('ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789', RAND()*34+1, 1),
                SUBSTRING('ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789', RAND()*34+1, 1),
                SUBSTRING('ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789', RAND()*34+1, 1),
                SUBSTRING('ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789', RAND()*34+1, 1),
                SUBSTRING('ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789', RAND()*34+1, 1),
                SUBSTRING('ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789', RAND()*34+1, 1),
                SUBSTRING('ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789', RAND()*34+1, 1)
                ) INTO @newUniqueValue;
        SET @rcount = -1;
        SET @query=CONCAT('SELECT COUNT(*) INTO @rcount FROM  ',tableName,' WHERE ',columnName,'  like ''',@newUniqueValue,'''');
        PREPARE stmt FROM  @query;
        EXECUTE stmt;
        DEALLOCATE PREPARE stmt;
    IF @rcount = 0 THEN
            SET uniqueValue = @newUniqueValue ;
        END IF ;
    END WHILE ;
    SELECT uniqueValue;
    END$$

DELIMITER ;

Verwenden Sie diese gespeicherte Prozedur und verwenden Sie sie jedes Mal wie

Call GenerateUniqueValue('tableName','columnName')
Hariramprasath Nandhagopalan
quelle
0

Ein einfacher Weg, um eine eindeutige Nummer zu generieren

set @i = 0;
update vehicles set plate = CONCAT(@i:=@i+1, ROUND(RAND() * 1000)) 
order by rand();
Gautier
quelle
0

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:

CREATE FUNCTION `random_string`(length SMALLINT(3), seed VARCHAR(255)) RETURNS varchar(255) CHARSET utf8
    NO SQL
BEGIN
    SET @output = '';

    IF seed IS NULL OR seed = '' THEN SET seed = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; END IF;

    SET @rnd_multiplier = LENGTH(seed);

    WHILE LENGTH(@output) < length DO
        # Select random character and add to output
        SET @output = CONCAT(@output, SUBSTRING(seed, RAND() * (@rnd_multiplier + 1), 1));
    END WHILE;

    RETURN @output;
END

Kann verwendet werden als:

SELECT random_string(10, '')

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:

SELECT random_string(10, '1234')
Maarten Ureel
quelle