我正在开发一款涉及车辆的游戏.我有一个名为"车辆"的MySQL表,其中包含有关车辆的数据,包括存储车辆牌照的"板"栏.
现在这里出现了我遇到问题的部分.我需要在创建新车辆之前找到未使用的车牌 - 它应该是一个字母数字8字符随机字符串.我是如何实现这一点的是在Lua中使用while循环,这是我正在编程的语言,用于生成字符串并查询DB以查看它是否被使用.然而,随着车辆数量的增加,我预计现在这种情况会变得更加低效.因此,我决定尝试使用MySQL查询解决此问题.
我需要的查询应该只生成一个8字符的字母数字字符串,该字符串不在表中.我再次想到了生成和检查循环方法,但我并没有将这个问题局限于那个问题,以防万一更有效.我已经能够通过定义一个包含所有允许的字符的字符串并随机地对它进行子字符串来生成字符串,仅此而已.
任何帮助表示赞赏.
Ran*_*eed 92
正如我在评论中所说,我不会为碰撞的可能性而烦恼.只需生成一个随机字符串并检查它是否存在.如果是这样,请再试一次,除非已经分配了大量的印版,否则你不应该多做几次.
另一种在pure(My)SQL中生成8个字符长的伪随机字符串的解决方案:
SELECT LEFT(UUID(), 8);
Run Code Online (Sandbox Code Playgroud)
您可以尝试以下(伪代码):
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
Run Code Online (Sandbox Code Playgroud)
Eug*_*eck 79
这个问题包含两个非常不同的子问题:
虽然很容易实现随机性,但没有重试循环的唯一性则不然.这使我们首先专注于独特性.非随机的唯一性可以通过以下方式实现AUTO_INCREMENT.所以使用保留唯一性,伪随机变换就可以了:
RAND(N)本身!保证由同一种子创建的一系列随机数
所以我们使用@ AndreyVolk或@ GordonLinoff的方法,但是使用种子 INT32:
例如,Assumin RAND是一个AUTO_INCREMENT col:
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;
Run Code Online (Sandbox Code Playgroud)
pau*_*aul 52
如何计算连续整数的MD5(或其他)哈希值,然后取前8个字符.
即
MD5(1) = c4ca4238a0b923820dcc509a6f75849b => c4ca4238
MD5(2) = c81e728d9d4c2f636f067f89cc14862c => c81e728d
MD5(3) = eccbc87e4b5ce2fe28308fd9f2a7baf3 => eccbc87e
Run Code Online (Sandbox Code Playgroud)
等等
警告:我不知道你可以在碰撞之前分配多少(但它将是一个已知的恒定值).
编辑:现在这是一个古老的答案,但我再次看到它的时间在我的手上,所以,从观察......
所有数字的机会= 2.35%
所有字母的机会= 0.05%
MD5(82945)="7b763dcb ..."时的第一次碰撞(与MD5(25302)相同的结果)
Pad*_*ann 28
创建一个随机字符串
这是一个用于创建给定长度的随机字符串的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
Run Code Online (Sandbox Code Playgroud)
用法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 ;
Run Code Online (Sandbox Code Playgroud)
Gor*_*off 23
这是一种方法,使用alpha数字作为有效字符:
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;
Run Code Online (Sandbox Code Playgroud)
请注意,不保证唯一性.你必须单独检查.
And*_*olk 14
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;
Run Code Online (Sandbox Code Playgroud)
Pau*_*gel 13
您可以使用以下命令生成随机字母数字字符串:
lpad(conv(floor(rand()*pow(36,8)), 10, 36), 8, 0);
Run Code Online (Sandbox Code Playgroud)
您可以在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 ;
Run Code Online (Sandbox Code Playgroud)
现在只需插入您的数据即可
insert into vehicles(col1, col2) values ('value1', 'value2');
Run Code Online (Sandbox Code Playgroud)
触发器将为plate列生成一个值.
如果列允许NULL,则以这种方式工作.如果您希望它为NOT NULL,则需要定义默认值
`plate` CHAR(8) NOT NULL DEFAULT 'default',
Run Code Online (Sandbox Code Playgroud)
如果大写字母数字不是你想要的,你也可以在触发器中使用任何其他随机字符串生成算法.但触发器将照顾到唯一性.
小智 8
对于由 8 个随机数和大小写字母组成的字符串,这是我的解决方案:
LPAD(LEFT(REPLACE(REPLACE(REPLACE(TO_BASE64(UNHEX(MD5(RAND()))), "/", ""), "+", ""), "=", ""), 8), 8, 0)
Run Code Online (Sandbox Code Playgroud)
从里到外解释:
RAND 生成 0 到 1 之间的随机数MD5 计算 (1) 的 MD5 总和,32 个字符来自 af 和 0-9UNHEX 将 (2) 转换为 16 个字节,值从 00 到 FFTO_BASE64 将 (3) 编码为 base64,来自 az 和 AZ 以及 0-9 的 22 个字符加上“/”和“+”,后跟两个“=”REPLACEs 删除了 (4) 中的“/”、“+”和“=”字符LEFT 从 (5) 中获取前 8 个字符,如果您的随机字符串中需要更多或更少的字符,请将 8 更改为其他字符LPAD如果长度小于 8 个字符,则在 (6) 的开头插入零;再次,如果需要,将 8 更改为其他内容小智 6
这是我的工作,生成 6 位数字并在 MySQL 中更新:
产生:
SELECT SUBSTRING(MD5(RAND()) FROM 1 FOR 6)
Run Code Online (Sandbox Code Playgroud)
更新:
UPDATE table_name
SET column_name = SUBSTRING(MD5(RAND()) FROM 1 FOR 6)
WHERE id = x12
Run Code Online (Sandbox Code Playgroud)
I 使用另一列中的数据生成“散列”或唯一字符串
UPDATE table_name SET column_name = Right( MD5(another_column_with_data), 8 )
Run Code Online (Sandbox Code Playgroud)
字母表中的 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))));
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
212423 次 |
| 最近记录: |