สร้างสตริงอักขระ 8 ตัวแบบสุ่มและไม่ซ้ำกันโดยใช้ MySQL


112

ฉันกำลังทำเกมที่เกี่ยวข้องกับยานพาหนะในบางจุด ฉันมีตาราง MySQL ชื่อ "ยานพาหนะ" ที่มีข้อมูลเกี่ยวกับยานพาหนะรวมถึงคอลัมน์ "แผ่นป้าย" ซึ่งเก็บป้ายทะเบียนสำหรับยานพาหนะ

ตอนนี้มาถึงส่วนที่ฉันมีปัญหา ฉันต้องหาป้ายทะเบียนที่ไม่ได้ใช้ก่อนที่จะสร้างรถคันใหม่ - ควรเป็นสตริงสุ่มแบบตัวเลขและตัวอักษร 8 อักขระ ฉันประสบความสำเร็จได้อย่างไรโดยใช้ while loop ใน Lua ซึ่งเป็นภาษาที่ฉันเขียนโปรแกรมเพื่อสร้างสตริงและสอบถาม DB เพื่อดูว่ามีการใช้หรือไม่ อย่างไรก็ตามเมื่อจำนวนยานพาหนะเพิ่มขึ้นฉันคาดว่าสิ่งนี้จะไม่มีประสิทธิภาพมากยิ่งขึ้นในตอนนี้ ดังนั้นฉันจึงตัดสินใจลองแก้ไขปัญหานี้โดยใช้แบบสอบถาม MySQL

แบบสอบถามที่ฉันต้องการควรสร้างสตริงตัวเลขและตัวอักษร 8 ตัวซึ่งยังไม่มีอยู่ในตาราง ฉันคิดถึงวิธีการสร้างและตรวจสอบลูปอีกครั้ง แต่ฉันไม่ได้ จำกัด คำถามนี้ไว้แค่นั้นในกรณีที่มีคำถามที่มีประสิทธิภาพมากกว่า ฉันสามารถสร้างสตริงได้โดยการกำหนดสตริงที่มีอักขระที่อนุญาตทั้งหมดและตั้งสตริงย่อยแบบสุ่มและไม่มีอะไรเพิ่มเติม

ขอความช่วยเหลือใด ๆ


คุณต้องการสิ่งเหล่านี้แบบสุ่มแค่ไหน? หากมีคนได้รับป้ายทะเบียนใดป้ายหนึ่งมีความสำคัญหรือไม่ว่าพวกเขาสามารถเขียนป้ายทะเบียนถัดไปหรือก่อนหน้าที่คุณมอบให้ได้
Damien_The_Unbeliever

@YaK ดูคำตอบของฉันเกี่ยวกับวิธีหลีกเลี่ยงความเป็นไปได้เล็กน้อยที่จะเกิดการปะทะกัน
Eugen Rieck

คำตอบ:


87

ปัญหานี้ประกอบด้วยสองปัญหาย่อยที่แตกต่างกันมาก:

  • สตริงต้องดูเหมือนสุ่ม
  • สตริงต้องไม่ซ้ำกัน

ในขณะที่การสุ่มทำได้ค่อนข้างง่าย แต่ความเป็นเอกลักษณ์ที่ไม่มีการวนซ้ำจะไม่เกิดขึ้น สิ่งนี้ทำให้เรามีสมาธิกับความเป็นเอกลักษณ์ก่อน ความเป็นเอกลักษณ์ที่ไม่สุ่มสามารถทำได้เล็กน้อยด้วยAUTO_INCREMENT. ดังนั้นการใช้การรักษาความเป็นเอกลักษณ์การแปลงแบบสุ่มหลอกก็ใช้ได้:

  • แฮชได้รับการแนะนำโดย @paul
  • การเข้ารหัส AES ก็เหมาะเช่นกัน
  • แต่มีสิ่งที่ดี: RAND(N)ตัวมันเอง!

ลำดับของตัวเลขสุ่มที่สร้างโดยเมล็ดพันธุ์เดียวกันรับประกันว่าจะเป็น

  • ทำซ้ำได้
  • แตกต่างกันสำหรับการทำซ้ำ 8 ครั้งแรก
  • ถ้าเมล็ดเป็น INT32

ดังนั้นเราจึงใช้แนวทางของ @ AndreyVolk หรือ @ GordonLinoff แต่ด้วยเมล็ด RAND :

เช่น Assumin idเป็นAUTO_INCREMENTคอลัมน์:

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;

วิธีการที่น่าสนใจมาก แต่คุณอาจหมายถึงRAND(LAST_INSERT_ID()); UPDATE vehicles (...) , rand()*36+1, (...)(หรือมิฉะนั้นจะส่งกลับ 8 เท่าของอักขระเดียวกัน) เราจะแน่ใจได้อย่างไรว่าการโทรติดต่อกัน 8 ครั้งrand()จะรับประกันว่าจะส่งคืนลำดับที่แตกต่างกันหากเริ่มต้นด้วยเมล็ดพันธุ์อื่น
RandomSeed

8
ฉันแค่สงสัย ทำไมคุณถึงใช้ตัวเลขเหล่านั้น ..4294967296)) * 36 + 1?
มิก

7
มันเก่าไปหน่อย แต่ฉันต้องการทราบว่าฉันต้องเพิ่มFLOOR()พารามิเตอร์สตริงย่อยที่สอง: substring('ABC … 789', floor(rand(@seed:= … )*36+1), 1), ในบางครั้งสตริงย่อยพยายามเลือกอักขระ 36.9 ซึ่งเมื่อปัดเศษเป็น 37 จะทำให้ไม่มีการเลือกอักขระ
Phillip Dodson

4
คุณไม่สามารถเรียกสตริงแบบสุ่มได้หากทำซ้ำได้ และยังสามารถทำซ้ำได้เนื่องจากคุณใช้floor()ไฟล์. นี้sqlfiddleแสดงว่ารายการที่ซ้ำกันถูกสร้างขึ้นสำหรับสตริงยาวสามอักขระ
Paul Spiegel

6
@EugenRieck ฉันไม่เข้าใจว่าคุณได้รับหมายเลขของคุณอย่างไร ("การทำซ้ำ 2 ^ 32 ครั้งแรก") แต่ฉันต้องการเพียงตัวอย่างเดียวของรายการที่ซ้ำกันเพื่อหักล้างแนวคิดนี้ สำหรับ ID 193844และ775771อัลกอริทึมของคุณจะสร้างสตริงเดียวกันT82X711(สาธิต )
Paul Spiegel

115

ฉันไม่กังวลกับโอกาสที่จะเกิดการปะทะกัน เพียงสร้างสตริงแบบสุ่มและตรวจสอบว่ามีอยู่หรือไม่ ถ้าเป็นเช่นนั้นให้ลองอีกครั้งและคุณไม่ควรทำมากกว่านั้นสองสามครั้งเว้นแต่คุณจะมีจานจำนวนมากที่กำหนดไว้แล้ว

อีกวิธีหนึ่งสำหรับการสร้างสตริงสุ่มหลอกแบบยาว 8 อักขระใน SQL (My) บริสุทธิ์:

SELECT LEFT(UUID(), 8);

คุณสามารถลองทำดังต่อไปนี้ (รหัสหลอก):

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

เนื่องจากโพสต์นี้ได้รับความสนใจในระดับที่ไม่คาดคิดให้ฉันเน้นความคิดเห็นของ ADTC : โค้ดด้านบนค่อนข้างโง่และสร้างตัวเลขตามลำดับ

สำหรับการสุ่มที่โง่น้อยกว่าเล็กน้อยให้ลองทำสิ่งนี้แทน:

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

และสำหรับการสุ่มที่แท้จริง (ปลอดภัยด้วยการเข้ารหัส) ให้ใช้ RANDOM_BYTES()แทนที่จะRAND() (แต่ฉันจะพิจารณาย้ายตรรกะนี้ขึ้นไปที่เลเยอร์แอปพลิเคชัน)


ขอบคุณสำหรับวิธีแก้ปัญหาของคุณฉันมีคำถามหนึ่งข้อเกี่ยวกับ UUID จำนวนโอกาสที่รหัสที่คุณสร้าง 8 อักขระจะเกิดซ้ำอีกครั้ง
TR-Ahmed

1
@ user3099183 อย่างเป็นทางการ "ต่ำมาก" 16 ^ 8 เป็นสตริงที่เป็นไปได้ประมาณ 4 พันล้านสตริง
RandomSeed

23
โปรดทราบว่าอักขระ 8 ตัวแรกของ UUID ไม่ได้เป็นแบบสุ่ม แต่เป็นลำดับเนื่องจากเป็นไปตามการประทับเวลา
ADTC

ฉันต้องการสร้างสตริงสุ่มยาว 9 อักขระและเมื่อฉันใช้9ในโค้ดของคุณSELECT LEFT(UUID(), 9);จะมี-ที่ท้ายสตริงที่สร้างเป็นอักขระที่เก้าเสมอ มันคงที่ ทำไม?
Martin AJ

3
@MartinAJ เพราะสตริงเป็นuuid คุณสามารถแทนที่ยัติภังค์ได้อย่างง่ายดายเช่นSELECT LEFT(REPLACE(UUID(), '-', ''), 16);
jchook

53

สิ่งที่เกี่ยวกับการคำนวณแฮช MD5 (หรืออื่น ๆ ) ของจำนวนเต็มตามลำดับจากนั้นใช้อักขระ 8 ตัวแรก

กล่าวคือ

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

เป็นต้น

ข้อแม้: ฉันไม่รู้ว่าคุณสามารถจัดสรรจำนวนเท่าใดก่อนที่จะเกิดการชนกัน (แต่จะเป็นค่าที่ทราบและคงที่)

แก้ไข: ตอนนี้เป็นคำตอบเก่า แต่ฉันเห็นมันอีกครั้งเมื่อเวลาผ่านไปดังนั้นจากการสังเกต ...

โอกาสของตัวเลขทั้งหมด = 2.35%

โอกาสของตัวอักษรทั้งหมด = 0.05%

การชนกันครั้งแรกเมื่อ MD5 (82945) = "7b763dcb ... " (ผลลัพธ์เดียวกับ MD5 (25302))


2
ความคิดที่ดีสามารถใช้กับคีย์หลัก จะเก็บไว้ในใจสำหรับโครงการในอนาคตขอบคุณ!
funstein

2
มีโอกาสที่สิ่งนี้อาจส่งผลด้วยตัวเลขเท่านั้น
Mladen Janjetovic

9
มันไม่สุ่มเลย
พอล

1
คุณสามารถทำให้มันเป็นแบบ "สุ่ม" ได้มากขึ้นหากแทนที่จะใช้รหัสที่เพิ่มขึ้นอัตโนมัติคุณจะใช้วันที่และเวลาในการแทรกซึ่งจะไม่ซ้ำกัน
Javier La Banca

35

สร้างสตริงแบบสุ่ม

นี่คือฟังก์ชัน MySQL เพื่อสร้างสตริงแบบสุ่มตามความยาวที่กำหนด

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

การใช้SELECT RANDSTRING(8)เพื่อส่งคืนสตริงอักขระ 8 ตัว

คุณสามารถปรับแต่งไฟล์@allowedChars.

ไม่รับประกันความเป็นเอกลักษณ์ - ดังที่คุณจะเห็นในความคิดเห็นเกี่ยวกับโซลูชันอื่น ๆ สิ่งนี้เป็นไปไม่ได้ แต่คุณจะต้องสร้างสตริงให้ตรวจสอบว่ามีการใช้งานอยู่หรือไม่แล้วลองอีกครั้งหากเป็นเช่นนั้น


ตรวจสอบว่ามีการใช้สตริงสุ่มแล้วหรือไม่

หากเราต้องการไม่ให้รหัสตรวจสอบการชนกันออกจากแอปเราสามารถสร้างทริกเกอร์ได้:

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 ;

6
นี่ควรเป็นคำตอบที่ยอมรับชัดเจนและตรงประเด็นทำงานได้ดีสำหรับฉันขอบคุณ @ paddy-mann
Saif

นี่เป็นทางออกที่ดีที่สุดที่ฉันคิด ขอบคุณ!
Pronoy999

24

นี่เป็นวิธีหนึ่งโดยใช้ตัวเลขอัลฟาเป็นอักขระที่ถูกต้อง:

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;

หมายเหตุไม่มีการรับประกันความเป็นเอกลักษณ์ คุณจะต้องตรวจสอบแยกต่างหาก


7
ใช้พื้น (แรนด์ () * 36 + 1) แทน มิฉะนั้นผลลัพธ์บางอย่างจะ 'สั้น'
Fraggle

2
ควรมี 35 + 1 ไม่ใช่ 36 + 1! มิฉะนั้นคุณจะได้รับสตริงที่มี 8 ตัวอักษรและบางตัวมี 7
BIOHAZARD

23

นี่เป็นอีกวิธีในการสร้างสตริงแบบสุ่ม:

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



14

คุณสามารถสร้างสตริงตัวอักษรและตัวเลขแบบสุ่มด้วย:

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

คุณสามารถใช้มันในBEFORE INSERTทริกเกอร์และตรวจสอบว่าซ้ำกันใน 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 ;

ตอนนี้เพียงแค่ใส่ข้อมูลของคุณเช่น

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

และทริกเกอร์จะสร้างค่าสำหรับ plateคอลัมน์

( การสาธิต sqlfiddle )

ซึ่งจะทำงานในลักษณะนี้หากคอลัมน์อนุญาตเป็น NULL หากคุณต้องการให้ไม่เป็นโมฆะคุณจะต้องกำหนดค่าเริ่มต้น

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

คุณยังสามารถใช้อัลกอริทึมการสร้างสตริงแบบสุ่มอื่น ๆ ในทริกเกอร์ได้หากตัวพิมพ์ใหญ่และตัวเลขคละกันไม่ใช่สิ่งที่คุณต้องการ แต่ทริกเกอร์จะดูแลความเป็นเอกลักษณ์


สุดทึ่ง! นี่คือสิ่งที่ฉันต้องการ ฉันแค่อยากจะเข้าใจว่ามันถูกแปลงเป็นสตริงได้อย่างไร เหตุใดจึงมีธารสิ่งที่ต้องทำเพื่อเพิ่มตัวเลขและอื่น ๆ ยังไงก็ขอขอบคุณ
Akxe

@Akxe Conv ()สามารถใช้เพื่อแปลงตัวเลขเป็นสตริงตัวอักษรและตัวเลข เป็นตัวเลขแสดงpow(36,8)-1 ZZZZZZZZดังนั้นเราจึงสร้างเป็นจำนวนเต็มสุ่มระหว่าง0และ '36 ^ 8-1' (จาก0ไป2821109907455) และแปลงเป็นตัวอักษรและตัวเลขระหว่างสตริง0และunsing ZZZZZZZZ lapad ()จะเติมสตริงด้วยศูนย์จนกว่าจะมีความยาว 8conv()
Paul Spiegel

คุณชายเป็นอัจฉริยะ ฉันคิดว่าการเพิ่มตัวอักษรขนาดเล็กนั้นเป็นไปไม่ได้เนื่องจากความไม่ต่อเนื่องของตัวอักษร? (91-96) ไม่ใช่ว่าฉันต้องการมันแค่อยากรู้ ...
Akxe

@Akxe conv()รองรับฐานได้สูงสุด 36 ตัวเท่านั้น (10 หลัก + 26 ตัวอักษรตัวพิมพ์ใหญ่) หากคุณต้องการรวมตัวอักษรพิมพ์เล็กคุณจะต้องมีวิธีอื่นในการแปลงตัวเลขเป็นสตริง
Paul Spiegel

คำเตือน: ใช้ไม่ได้กับ str_len> 13 ตั้งแต่วันที่ 14 เป็นต้นไปคุณจะได้รับ '3W5E11264SGSF' เสมอ ;-)
Gerard H. Pille


5

ฉันใช้ข้อมูลจากคอลัมน์อื่นเพื่อสร้าง "แฮช" หรือสตริงเฉพาะ

UPDATE table_name SET column_name = Right( MD5(another_column_with_data), 8 )

5

สำหรับสตริงที่ประกอบด้วยตัวเลขสุ่ม 8 ตัวและตัวอักษรตัวบนและตัวพิมพ์เล็กนี่คือทางออกของฉัน:

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

อธิบายจากภายในสู่ภายนอก:

  1. RAND สร้างตัวเลขสุ่มระหว่าง 0 ถึง 1
  2. MD5 คำนวณผลรวม MD5 ของ (1), 32 อักขระจาก af และ 0-9
  3. UNHEX แปล (2) เป็น 16 ไบต์โดยมีค่าตั้งแต่ 00 ถึง FF
  4. TO_BASE64 เข้ารหัส (3) เป็น base64 อักขระ 22 ตัวจาก az และ AZ และ 0-9 บวก "/" และ "+" ตามด้วย "=" สองตัว
  5. ทั้งสามตัวREPLACEลบอักขระ "/", "+" และ "=" จาก (4)
  6. LEFT ใช้อักขระ 8 ตัวแรกจาก (5) เปลี่ยน 8 เป็นอย่างอื่นหากคุณต้องการอักขระมากกว่าหรือน้อยกว่าในสตริงสุ่มของคุณ
  7. LPADแทรกศูนย์ที่จุดเริ่มต้นของ (6) หากมีความยาวน้อยกว่า 8 อักขระ อีกครั้งเปลี่ยน 8 เป็นอย่างอื่นหากจำเป็น

เยี่ยมมากสิ่งที่ฉันกำลังมองหาเพื่อสร้าง ID ที่เหมือนโทเค็นโดยกำเนิดใน MySQL
rabudde

4

8 ตัวอักษรจากตัวอักษร - ตัวพิมพ์ใหญ่ทั้งหมด:

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

3

หากคุณไม่มี id หรือ seed เช่นมันสำหรับรายการค่าในการแทรก:

REPLACE(RAND(), '.', '')

2

วิธีแก้ปัญหาที่ง่ายและมีประสิทธิภาพในการรับสตริง 10 อักขระแบบสุ่มพร้อมตัวอักษรตัวพิมพ์ใหญ่และตัวพิมพ์เล็กและตัวเลข:

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

1

หากคุณพอใจกับป้ายทะเบียนแบบ "สุ่ม" แต่คาดเดาได้ทั้งหมดคุณสามารถใช้ทะเบียนกะการตอบกลับเชิงเส้นเพื่อเลือกหมายเลขป้ายทะเบียนถัดไป - รับประกันว่าจะผ่านทุกหมายเลขก่อนที่จะทำซ้ำ อย่างไรก็ตามหากไม่มีการคำนวณที่ซับซ้อนคุณจะไม่สามารถอ่านสตริงตัวเลขและตัวอักษรทุกๆ 8 อักขระได้ (คุณจะได้รับ 2 ^ 41 จากเพลตที่เป็นไปได้ 36 ^ 8 (78%) 2 ^ 41) เพื่อให้สิ่งนี้เติมเต็มพื้นที่ของคุณให้ดีขึ้นคุณสามารถแยกตัวอักษรออกจากจาน (อาจเป็น O) ให้คุณได้ 97%


1

เมื่อพิจารณาถึงจำนวนอักขระทั้งหมดที่คุณต้องการคุณจะมีโอกาสน้อยมากที่จะสร้างป้ายทะเบียนที่เหมือนกันสองแผ่น ดังนั้นคุณอาจหลีกเลี่ยงการสร้างตัวเลขใน LUA

คุณมีแผ่นตัวเลขที่แตกต่างกัน 36 ^ 8 (2,821,109,907,456 นั่นเป็นจำนวนมาก) แม้ว่าคุณจะมีแผ่นตัวเลขเป็นล้านแล้ว แต่คุณก็มีโอกาสน้อยมากที่จะสร้างแผ่นงานที่คุณมีอยู่แล้วประมาณ 0.000035%

แน่นอนว่าทั้งหมดขึ้นอยู่กับจำนวนแผ่นตัวเลขที่คุณจะสร้าง


จริงฉันจะทำต่อไปในเกมจริงแทน SQL ขอบคุณมาก.
funstein

1

ฟังก์ชันนี้จะสร้างสตริงสุ่มตามความยาวอินพุตของคุณและอักขระที่อนุญาตเช่นนี้:

SELECT str_rand(8, '23456789abcdefghijkmnpqrstuvwxyz');

รหัสฟังก์ชัน:

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 ;

รหัสนี้อ้างอิงจากฟังก์ชันสตริงแบบสุ่มที่ส่งโดย "Ross Smith II"


ฟังก์ชันนี้จะไม่สร้างค่าเฉพาะแบบสุ่ม
Faisal

1

ในการสร้างตัวเลขและตัวอักษรแบบสุ่ม10 หลักโดยไม่รวมตัวอักษรที่เหมือนกัน 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)

นี่คือสิ่งที่ฉันต้องการจะสร้างรหัสบัตรกำนัล อักขระที่สับสนจะถูกลบออกเพื่อลดข้อผิดพลาดเมื่อพิมพ์ลงในแบบฟอร์มรหัสบัตรกำนัล

หวังนี้จะช่วยให้ใครสักคนที่อยู่บนพื้นฐานของคำตอบที่ยอดเยี่ยม ม.ค. Uhlig ของ

โปรดดูคำตอบของ Jan เพื่อดูรายละเอียดวิธีการทำงานของรหัสนี้


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 ;

ใช้กระบวนงานที่เก็บไว้นี้และใช้ทุกครั้งเช่น

Call GenerateUniqueValue('tableName','columnName')



0

ฉันกำลังมองหาสิ่งที่คล้ายกันและฉันตัดสินใจที่จะสร้างเวอร์ชันของตัวเองซึ่งคุณสามารถระบุเมล็ดพันธุ์อื่นได้หากต้องการ (รายการตัวละคร) เป็นพารามิเตอร์:

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

สามารถใช้เป็น:

SELECT random_string(10, '')

ซึ่งจะใช้ seed ในตัวของอักขระตัวพิมพ์ใหญ่และตัวพิมพ์เล็ก + หลัก NULL จะเป็นค่าแทน ""

แต่สามารถระบุเมล็ดพันธุ์ที่กำหนดเองได้ขณะโทร:

SELECT random_string(10, '1234')
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.