Generowanie losowego i unikalnego ciągu 8 znaków przy użyciu MySQL

111

Pracuję nad grą, która w pewnym momencie dotyczy pojazdów. Mam tabelę MySQL o nazwie „pojazdy” zawierającą dane o pojazdach, w tym kolumnę „tablica rejestracyjna”, która przechowuje tablice rejestracyjne pojazdów.

Teraz nadchodzi część, z którą mam problemy. Muszę znaleźć nieużywaną tablicę rejestracyjną przed utworzeniem nowego pojazdu - powinien to być alfanumeryczny 8-znakowy losowy ciąg. Jak to osiągnąłem, wykorzystałem pętlę while w Lua, czyli języku, w którym programuję, do generowania ciągów i wysyłania zapytań do bazy danych, aby sprawdzić, czy jest używana. Jednak wraz ze wzrostem liczby pojazdów spodziewam się, że stanie się to jeszcze bardziej nieefektywne, jak jest teraz. Dlatego zdecydowałem się spróbować rozwiązać ten problem za pomocą zapytania MySQL.

Zapytanie, którego potrzebuję, powinno po prostu wygenerować 8-znakowy ciąg alfanumeryczny, którego nie ma jeszcze w tabeli. Ponownie pomyślałem o podejściu do tworzenia i sprawdzania pętli, ale nie ograniczam tego pytania do tego, na wypadek gdyby było bardziej wydajne. Udało mi się wygenerować ciągi znaków, definiując ciąg zawierający wszystkie dozwolone znaki i losowo składający się z niego, i nic więcej.

Każda pomoc jest mile widziana.

funstein
źródło
Jak przypadkowe mają być? Jeśli ktoś otrzyma konkretną tablicę rejestracyjną, czy jest ważne, czy nie może opracować następnej lub poprzedniej tablicy rejestracyjnej, którą rozdałeś?
Damien_The_Unbeliever
@YaK Zobacz moją odpowiedź, jak uniknąć nawet najmniejszej możliwości kolizji
Eugen Rieck

Odpowiedzi:

87

Ten problem składa się z dwóch bardzo różnych podproblemów:

  • ciąg musi być pozornie przypadkowy
  • ciąg musi być unikalny

Chociaż przypadkowość jest dość łatwa do osiągnięcia, unikalność bez pętli ponawiania już nie. To prowadzi nas do skoncentrowania się najpierw na wyjątkowości. Nieprzypadkową wyjątkowość można w trywialny sposób osiągnąć za pomocą AUTO_INCREMENT. Tak więc użycie pseudolosowej transformacji zachowującej niepowtarzalność byłoby w porządku:

  • Hash został zasugerowany przez @paul
  • Szyfrowanie AES również pasuje
  • Ale jest fajny: RAND(N)sam!

Gwarantujemy, że sekwencja liczb losowych utworzona przez to samo ziarno będzie

  • odtwarzalny
  • różny dla pierwszych 8 iteracji
  • jeśli ziarno jest INT32

Więc używamy podejścia @ AndreyVolk lub @ GordonLinoff, ale z rozstawionym RAND :

np. Assumin idto AUTO_INCREMENTkolumna:

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
źródło
Bardzo ciekawe podejście, ale prawdopodobnie miałeś na myśli RAND(LAST_INSERT_ID()); UPDATE vehicles (...) , rand()*36+1, (...)(inaczej zwraca 8 razy ten sam znak). Jak możemy być pewni, że 8 kolejnych wywołań funkcji rand()gwarantuje zwrócenie innej sekwencji, jeśli zostanie zainicjowane innym ziarnem?
RandomSeed
8
Właśnie się zastanawiałem. Dlaczego używasz tych numerów ..4294967296)) * 36 + 1?
Mick,
7
Jest to trochę stare, ale chciałbym zauważyć, że musiałem dodać FLOOR()wokół drugiego podłańcucha parametry: substring('ABC … 789', floor(rand(@seed:= … )*36+1), 1), W niektórych przypadkach podciąg próbował wybrać znak 36.9, który po zaokrągleniu do 37 nie powodowałby wybierania żadnego znaku.
Phillip Dodson,
4
Nie możesz wywołać łańcucha losowo, jeśli jest odtwarzalny. Możliwe są również duplikaty, ponieważ używaszfloor() . To sqlfiddle pokazuje, że duplikaty są tworzone dla trzech ciągów znaków.
Paul Spiegel
6
@EugenRieck Nie rozumiem, w jaki sposób otrzymujesz swoje liczby („pierwsze 2 ^ 32 iteracje”). Ale potrzebuję tylko jednego przykładu duplikatów, aby obalić tę koncepcję. Dla identyfikatorów 193844i 775771algorytmu wygeneruje ten sam ciąg T82X711( demo ).
Paul Spiegel,
114

Nie zawracałbym sobie głowy prawdopodobieństwem kolizji. Po prostu wygeneruj losowy ciąg i sprawdź, czy istnieje. Jeśli tak, spróbuj ponownie i nie powinieneś robić tego więcej niż kilka razy, chyba że masz już przypisaną ogromną liczbę tablic.

Inne rozwiązanie do generowania 8-znakowego pseudolosowego ciągu w czystym (My) SQL:

SELECT LEFT(UUID(), 8);

Możesz wypróbować następujący (pseudokod):

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

Ponieważ ten post zyskał nieoczekiwany poziom uwagi, pozwolę sobie podkreślić komentarz ADTC : powyższy fragment kodu jest dość głupi i tworzy kolejne cyfry.

Aby uzyskać nieco mniej głupią przypadkowość, spróbuj zamiast tego czegoś takiego:

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

Aby uzyskać prawdziwą (kryptograficznie bezpieczną) losowość, użyj RANDOM_BYTES()zamiast RAND()(ale wtedy rozważę przeniesienie tej logiki do warstwy aplikacji).

RandomSeed
źródło
Dziękuję za rozwiązanie. Mam jedno pytanie dotyczące UUID. ile jest szans, że identyfikator wygenerowany przez 8 znaków zostanie ponownie powtórzony.
TR-Ahmed
1
@ user3099183 Oficjalnie „bardzo niski”. 16 ^ 8 to około 4 miliardy możliwych ciągów.
RandomSeed
23
Należy pamiętać, że pierwszych 8 znaków UUID nie jest przypadkowych, ale sekwencyjnych, ponieważ jest oparty na sygnaturze czasowej.
ADTC
Chcę wygenerować losowy ciąg o długości 9 znaków, a kiedy używam 9w kodzie SELECT LEFT(UUID(), 9);, -na końcu wygenerowanego ciągu zawsze znajduje się dziewiąty znak. To jest stałe. Czemu?
Martin AJ
3
@MartinAJ ponieważ ciąg jest UUID . Możesz łatwo zamienić myślniki np.SELECT LEFT(REPLACE(UUID(), '-', ''), 16);
jchook
53

A co z obliczeniem wartości skrótu MD5 (lub innego) sekwencyjnych liczb całkowitych, a następnie pobraniem pierwszych 8 znaków.

to znaczy

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

itp.

Uwaga: nie mam pojęcia, ile można przydzielić przed kolizją (ale byłaby to znana i stała wartość).

edycja: To jest teraz stara odpowiedź, ale widziałem ją ponownie z czasem na moich rękach, więc z obserwacji ...

Szansa na wszystkie liczby = 2,35%

Szansa na wszystkie litery = 0,05%

Pierwsza kolizja, gdy MD5 (82945) = "7b763dcb ..." (taki sam wynik jak MD5 (25302))

Paweł
źródło
2
Dobry pomysł, można go użyć na kluczu podstawowym. Będę o tym pamiętać przy przyszłych projektach, dzięki!
funstein
2
Jest szansa, że ​​może to wyniknąć z
samych
9
To wcale nie jest przypadkowe.
paul
1
Możesz uczynić to bardziej „losowym”, jeśli zamiast używać automatycznego inkrementalnego identyfikatora, użyjesz daty i godziny, w której dokonano wstawiania, która również jest unikalna.
Javier La Banca
35

Utwórz losowy ciąg

Oto funkcja MySQL do tworzenia losowego ciągu o określonej długości.

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

Stosowanie SELECT RANDSTRING(8) do zwrócenia ciągu 8 znaków.

Możesz dostosować @allowedChars .

Wyjątkowość nie jest gwarantowana - jak zobaczysz w komentarzach do innych rozwiązań, po prostu nie jest to możliwe. Zamiast tego musisz wygenerować ciąg, sprawdzić, czy jest już używany, i spróbować ponownie, jeśli jest.


Sprawdź, czy losowy ciąg jest już używany

Jeśli chcemy zachować kod sprawdzający kolizje poza aplikacją, możemy stworzyć wyzwalacz:

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
źródło
6
to powinna być zaakceptowana odpowiedź, jasna i na temat, działała dobrze dla mnie, dzięki @ paddy-mann
Saif
Myślę, że to najlepsze rozwiązanie. Dzięki!
Pronoy999
23

Oto jeden sposób, używając cyfr alfanumerycznych jako prawidłowych znaków:

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;

Uwaga: nie ma gwarancji wyjątkowości. Musisz to sprawdzić osobno.

Gordon Linoff
źródło
7
zamiast tego użyj floor (rand () * 36 + 1). W przeciwnym razie niektóre wyniki będą „krótkie”.
Fraggle
2
powinno być 35 + 1, a nie 36 + 1! W przeciwnym razie dostaniesz kilka strun z 8 znakami, a niektóre z 7
BIOHAZARD
23

Oto inna metoda generowania losowego ciągu:

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

bealex
źródło
16

Możesz użyć funkcji rand () i char () MySQL :

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
źródło
14

Możesz wygenerować losowy ciąg alfanumeryczny za pomocą:

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

Możesz użyć go w BEFORE INSERTwyzwalaczu i sprawdzić duplikat w pętli while:

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 ;

Teraz po prostu wstaw swoje dane, takie jak

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

Wyzwalacz wygeneruje wartość dla platekolumny.

( demo sqlfiddle )

Działa to w ten sposób, jeśli kolumna dopuszcza wartości NULL. Jeśli chcesz, aby NIE było NULL, musisz zdefiniować wartość domyślną

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

Możesz także użyć dowolnego innego algorytmu generowania losowych ciągów w wyzwalaczu, jeśli duże litery alfanumeryczne nie są tym, czego chcesz. Ale wyzwalacz zadba o wyjątkowość.

Paul Spiegel
źródło
Niesamowity! To jest dokładnie to, czego chciałem. Chciałbym tylko zrozumieć, w jaki sposób jest konwertowany na ciąg. Dlaczego jest pow, co robić, dodawać liczby i tak dalej. W każdym razie dziękuję.
Akxe
@Akxe conv () może służyć do konwersji liczby na ciąg alfanumeryczny. pow(36,8)-1jest liczbową reprezentacją ZZZZZZZZ. Więc generujemy losową liczbę całkowitą z przedziału od 0„36 ^ 8-1” (od 0do 2821109907455) i konwertujemy ją na ciąg alfanumeryczny między 0i ZZZZZZZZunsing conv(). lapad () wypełni ciąg zerami, aż osiągnie długość 8.
Paul Spiegel,
Pan jest geniuszem. Wyobrażam sobie, że dodanie małych liter jest niemożliwe ze względu na nieciągłość znaków? (91-96) Nie żebym tego potrzebował, po prostu ciekawy ...
Akxe,
@Akxe conv()obsługuje tylko bazę do 36 (10 cyfr + 26 wielkich liter). Jeśli chcesz uwzględnić małe litery, będziesz potrzebować innego sposobu konwersji liczby na ciąg.
Paul Spiegel
Uwaga: nie działa dla str_len> 13. Od 14 roku zawsze otrzymujesz '3W5E11264SGSF'. ;-)
Gerard H. Pille
6

Aby wygenerować losowy ciąg, możesz użyć:

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

Otrzymujesz coś takiego:

353E50CC

Nikita G.
źródło
5

Oto moje rozwiązanie dla łańcucha składającego się z 8 liczb losowych oraz wielkich i małych liter:

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

Wyjaśnione od wewnątrz:

  1. RAND generuje liczbę losową od 0 do 1
  2. MD5 oblicza sumę MD5 (1), 32 znaki z af i 0-9
  3. UNHEX tłumaczy (2) na 16 bajtów z wartościami od 00 do FF
  4. TO_BASE64 koduje (3) jako base64, 22 znaki od az i AZ oraz 0-9 plus „/” i „+”, po których następuje dwa „=”
  5. te trzy REPLACEusuwają znaki „/”, „+” i „=” z (4)
  6. LEFT pobiera pierwsze 8 znaków z (5), zmień 8 na coś innego, jeśli potrzebujesz więcej lub mniej znaków w losowym ciągu
  7. LPADwstawia zera na początku (6), jeśli ma mniej niż 8 znaków; ponownie, w razie potrzeby zmień 8 na coś innego
Jan Uhlig
źródło
Świetnie, dokładnie to, czego szukałem, aby utworzyć identyfikator podobny do tokena natywnie w MySQL
rabudde
4

I Użyj danych z innej kolumny, aby wygenerować „hash” lub unikalny ciąg

UPDATE table_name SET column_name = Right( MD5(another_column_with_data), 8 )
Richard Fragiacomo
źródło
4

8 liter alfabetu - wielkie litery:

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
źródło
3

Jeśli nie masz identyfikatora lub ziarna, tak jak jest to lista wartości we wstawieniu:

REPLACE(RAND(), '.', '')
ekerner
źródło
2

Proste i wydajne rozwiązanie umożliwiające uzyskanie losowego ciągu 10 znaków z dużymi i małymi literami oraz cyframi:

select substring(base64_encode(md5(rand())) from 1+rand()*4 for 10);
Antares
źródło
1

Jeśli nie masz nic przeciwko „losowym”, ale całkowicie przewidywalnym tablicom rejestracyjnym, możesz użyć rejestru przesuwnego z liniowym sprzężeniem zwrotnym, aby wybrać następny numer rejestracyjny - gwarantujemy, że przejdziesz przez każdy numer przed powtórzeniem. Jednak bez skomplikowanej matematyki nie będziesz w stanie przejść przez każdy 8-znakowy ciąg alfanumeryczny (otrzymasz 2 ^ 41 z 36 ^ 8 (78%) możliwych tablic). Aby lepiej wypełniało to twoją przestrzeń, możesz wykluczyć literę z tablic (może O), co daje 97%.

τεκ
źródło
1

Biorąc pod uwagę całkowitą liczbę potrzebnych postaci, miałbyś bardzo małą szansę na wygenerowanie dwóch dokładnie podobnych tablic rejestracyjnych. W ten sposób prawdopodobnie mógłbyś uciec z generowaniem liczb w LUA.

Masz 36 ^ 8 różnych unikalnych numerów rejestracyjnych (2821,109,907,456, to dużo), nawet gdybyś miał już milion numerów, masz bardzo małą szansę na wygenerowanie takiej, którą już masz, około 0,000035%

Oczywiście wszystko zależy od tego, ile numerów rejestracyjnych ostatecznie utworzysz.

Lawrence Andrews
źródło
To prawda, będę to robić w grze zamiast w SQL. Dziękuję Ci bardzo.
funstein
1

Ta funkcja generuje losowy ciąg na podstawie długości wejściowej i dozwolonych znaków, takich jak:

SELECT str_rand(8, '23456789abcdefghijkmnpqrstuvwxyz');

kod funkcji:

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 ;

Ten kod jest oparty na funkcji shuffle string wysyłanej przez „Ross Smith II”

Mahoor13
źródło
Ta funkcja nie wygeneruje losowej unikalnej wartości.
Faisal
1

Aby utworzyć losowy 10-cyfrowy alfanumeryczny , z wyłączeniem podobnych znaków 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)

Właśnie tego potrzebowałem, aby utworzyć kod kuponu . Mylące znaki są usuwane, aby zmniejszyć liczbę błędów podczas wpisywania ich w formularzu kodu kuponu.

Mam nadzieję, że to komuś pomoże, na podstawie błyskotliwej odpowiedzi Jana Uhliga .

Zobacz odpowiedź Jana, aby dowiedzieć się, jak działa ten kod.

Paul Harris
źródło
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 ;

Użyj tej procedury składowanej i używaj jej za każdym razem, jak

Call GenerateUniqueValue('tableName','columnName')
Hariramprasath Nandhagopalan
źródło
0

Prosty sposób na wygenerowanie unikalnego numeru

set @i = 0;
update vehicles set plate = CONCAT(@i:=@i+1, ROUND(RAND() * 1000)) 
order by rand();
Gautier
źródło
0

Szukałem czegoś podobnego i postanowiłem stworzyć własną wersję, w której możesz również określić inne ziarno, jeśli chcesz (lista znaków) jako parametr:

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

Może być używany jako:

SELECT random_string(10, '')

Który użyłby wbudowanego materiału siewnego wielkich i małych liter + cyfr. NULL byłoby również wartością zamiast „”.

Ale można określić niestandardowe ziarno podczas wywoływania:

SELECT random_string(10, '1234')
Maarten Ureel
źródło