5

我有一个简单的表,其中的字段名为"hash" VARCHAR 10 UNIQUE FIELD

现在我想运行一个查询并自动生成字段内的哈希值。

问题是哈希必须是字母数字,并且必须是长 10 个字符和唯一的。

表结构:

CREATE TABLE `vouchers` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `hash` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `hash` (`hash`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

所以我需要在散列字段中插入散列,它们应该看起来像随机字母数字随机散列,我的意思是用户不应该只看一个散列就可以捕捉到下一个或上一个散列,而且它们必须是 10 个字符长且唯一。

有人对此有任何线索吗?

4

5 回答 5

4
-- most elegant, has adjustable length 1-32 and probably has best performance
SELECT SUBSTR(REPLACE(UUID(),'-',''),1,10) as randomStringUUID
;

-- generate 10 character [a-z0-9] string, has adjustable letter/nr ratio
SELECT CONCAT(
  CASE WHEN RAND()>=0.5 THEN char(round(RAND()*9+48)) ELSE char(round(RAND()*25+97)) END
  ,CASE WHEN RAND()>=0.5 THEN char(round(RAND()*9+48)) ELSE char(round(RAND()*25+97)) END
  ,CASE WHEN RAND()>=0.5 THEN char(round(RAND()*9+48)) ELSE char(round(RAND()*25+97)) END
  ,CASE WHEN RAND()>=0.5 THEN char(round(RAND()*9+48)) ELSE char(round(RAND()*25+97)) END
  ,CASE WHEN RAND()>=0.5 THEN char(round(RAND()*9+48)) ELSE char(round(RAND()*25+97)) END
  ,CASE WHEN RAND()>=0.5 THEN char(round(RAND()*9+48)) ELSE char(round(RAND()*25+97)) END
  ,CASE WHEN RAND()>=0.5 THEN char(round(RAND()*9+48)) ELSE char(round(RAND()*25+97)) END
  ,CASE WHEN RAND()>=0.5 THEN char(round(RAND()*9+48)) ELSE char(round(RAND()*25+97)) END
  ,CASE WHEN RAND()>=0.5 THEN char(round(RAND()*9+48)) ELSE char(round(RAND()*25+97)) END
  ,CASE WHEN RAND()>=0.5 THEN char(round(RAND()*9+48)) ELSE char(round(RAND()*25+97)) END
  ) as randomString
;

-- as bonus: generate a variable size letter only string, best for emulating names/words
SELECT SUBSTR(CONCAT(char(RAND()*25+55),char(RAND()*25+97),char(RAND()*25+97),char(RAND()*25+97),char(RAND()*25+97),char(RAND()*25+97),char(RAND()*25+97),char(RAND()*25+97),char(RAND()*25+97),char(RAND()*25+97),char(RAND()*25+97),char(RAND()*25+97)),1,RAND()*9+4) as RandomName

http://sqlfiddle.com/#!8/d41d8/586进行测试

于 2014-09-10T22:40:21.083 回答
3

这是将上面戈登的答案包装成一个函数的代码(归功于戈登)-

delimiter |
create function hash10() returns varchar(10)
begin
declare chars varchar(36);
set chars = '0123456789abcdefghijklmnopqrstuvwxyz';
return concat(substring(chars, floor(rand()*36) + 1, 1),
              substring(chars, floor(rand()*36) + 1, 1),
              substring(chars, floor(rand()*36) + 1, 1),
              substring(chars, floor(rand()*36) + 1, 1),
              substring(chars, floor(rand()*36) + 1, 1),
              substring(chars, floor(rand()*36) + 1, 1),
              substring(chars, floor(rand()*36) + 1, 1),
              substring(chars, floor(rand()*36) + 1, 1),
              substring(chars, floor(rand()*36) + 1, 1),
              substring(chars, floor(rand()*36) + 1, 1)
             );
end|
delimiter ;

然后你可以使用...

insert into x (hash) values (hash10()),(hash10()),(hash10());
于 2013-08-31T14:33:17.930 回答
2

我认为最好从应用程序逻辑处理这个问题。

如果您想以 sql 方式处理它,请尝试使用 mysql 函数UUID()(但生成的 uuid 长度为 36 个字符)

于 2013-08-31T13:13:56.173 回答
2

如果要为该字段创建唯一值,可以使用自动递增方法,仅以 36 为基数。这是一个高达数亿不同值的示例:

update t cross join (select @i := 0, @chars = '0123456789abcdefghijklmnopqrstuvwxyz') const
    set hash = concat(substring(@chars, ((@i := @i + 1) %36)+1, 1),
                      substring(@chars, floor(@i/pow(36, 1))%36 + 1, 1),
                      substring(@chars, floor(@i/pow(36, 2))%36 + 1, 1),
                      substring(@chars, floor(@i/pow(36, 3))%36 + 1, 1),
                      substring(@chars, floor(@i/pow(36, 4))%36 + 1, 1),
                      substring(@chars, floor(@i/pow(36, 5))%36 + 1, 1),
                      '0000'
                     );

编辑:(基于修改后的问题)

你的表有一个唯一的约束。我只会做以下事情:

insert into vouchers(hash)
    select concat(substring(@chars, floor(rand()*36) + 1, 1),
                  substring(@chars, floor(rand()*36) + 1, 1),
                  substring(@chars, floor(rand()*36) + 1, 1),
                  substring(@chars, floor(rand()*36) + 1, 1),
                  substring(@chars, floor(rand()*36) + 1, 1),
                  substring(@chars, floor(rand()*36) + 1, 1),
                  substring(@chars, floor(rand()*36) + 1, 1),
                  substring(@chars, floor(rand()*36) + 1, 1),
                  substring(@chars, floor(rand()*36) + 1, 1),
                  substring(@chars, floor(rand()*36) + 1, 1)
                 );

只需在循环中(或根据需要)多次执行此操作即可填充表格。您极不可能得到重复项。如果这样做,该特定插入将失败。

于 2013-08-31T13:40:59.777 回答
1

只需使用一个循环:

DROP FUNCTION hash10;
DELIMITER |
CREATE FUNCTION hash10() RETURNS VARCHAR(10)
BEGIN
  DECLARE chars VARCHAR(36);
  DECLARE result VARCHAR(10);
  DECLARE i INT;
  SET chars = '0123456789abcdefghijklmnopqrstuvwxyz';
  SET result = '';
  SET i = 0;
  label: LOOP
    SET result = CONCAT(result, SUBSTRING(chars, FLOOR(RAND()*36) + 1, 1));
    SET i = i + 1;
    IF i = 10 THEN
      LEAVE label;
    END IF;
  END LOOP label;
  RETURN result;
END|
DELIMITER ;

要生成不同的长度,只需将所有的10' 替换为不同的数字。

于 2015-11-13T17:28:38.573 回答