如何在MySQL上生成具有唯一字符序列的触发器?
o/ 我想生成一个4个字符的序列,使用大小写+数字。。但是我想在MySQL数据库上插入新用户之前,使用触发器生成这个序列 类似于=“Ae5f”或“5Bd2”的内容 我正在使用如何在MySQL上生成具有唯一字符序列的触发器?,mysql,triggers,Mysql,Triggers,o/ 我想生成一个4个字符的序列,使用大小写+数字。。但是我想在MySQL数据库上插入新用户之前,使用触发器生成这个序列 类似于=“Ae5f”或“5Bd2”的内容 我正在使用 CHAR( FLOOR(65 + (RAND() * 25))), CHAR( FLOOR(65 + (RAND() * 25))), CHAR( FLOOR(65 + (RAND() * 25))), CHAR( FLOOR(65 + (RAND() * 25))) 因此,代码将只生成4位大写字母,而不
CHAR( FLOOR(65 + (RAND() * 25))),
CHAR( FLOOR(65 + (RAND() * 25))),
CHAR( FLOOR(65 + (RAND() * 25))),
CHAR( FLOOR(65 + (RAND() * 25)))
因此,代码将只生成4位大写字母,而不是唯一的值,有时会返回“重复条目”
有人能帮我吗
-----------------------编辑-----------------------
我在Base32中的最后一个实现
CREATE DEFINER=`root`@`localhost` TRIGGER `healthcare`.`TESTE_BEFORE_INSERT` BEFORE INSERT ON `teste` FOR EACH ROW
BEGIN
DECLARE last_id integer;
SET last_id = (SELECT MAX(ID) AS lastID FROM `healthcare`.`teste`);
IF last_id IS NULL THEN
SET last_id = 0;
END IF;
SET NEW.USER_KEY = conv((1048575-last_id), 10, 32); /* 1048575 = VVVV */
END
随机化解决方案将受到欢迎。这是一个你可能会感兴趣的程序。其概念是为各种序列(在系统范围内使用)提供一个控制表。简言之,以下是一个卑鄙的人。它使用MySQL“意向锁” 您需要的是
Base36
数字功能,这就提供了其中的一部分。如何将其嵌入到设置中,如果您这样做,则取决于您
控制表:
-- drop table if exists sequences;
create table sequences
( -- the numbers in here are the next numbers free to use
-- so it is yours once you acquire the INTENTION lock
-- but do an UPDATE for the next guy by incrementing the number
-- and COMMIT
id int auto_increment primary key,
sectionType varchar(200) not null,
nextSequence int not null,
unique key(sectionType) -- perhaps overkill on index but meh
);
-- truncate table sequences;
insert sequences (sectionType,nextSequence) values
('Chassis Serial Number',1),('Engine Block Serial Number',1),('base36number',0);
存储过程:
DROP PROCEDURE IF EXISTS getBase36;
DELIMITER $$CREATE PROCEDURE getBase36
( OUT sOutVar CHAR(4) -- out parameter for base36 number
)
BEGIN
DECLARE num_to_use INT;
DECLARE i1,i2 INT;
DECLARE sSendBack CHAR(4);
-- 0-9 is ascii 48 to 57
-- A-Z is ascii 65 to 90
-- 0000 to ZZZZ in that order. 0 to 9 then A etc 36 positions
-- first char is 0. 36th char is Z. Base36, 0 is 0000 , 35 is 000Z, 36 is 00010
-- 1.68M possibilities
-- output ranges from 0000 to ZZZZ
START TRANSACTION;
SELECT nextSequence into num_to_use from sequences where sectionType='base36number' FOR UPDATE;
UPDATE sequences set nextSequence=nextSequence+1 where sectionType='base36number';
COMMIT; -- because of this, it cannot be a FUNCTION but must be a stored proc, else error 1422
-- which is Error 1422: Explicit or implicit commit is not allowed in a stored function or trigger
SET sOutVar='';
-- IF num_to_use>1679616 THEN
-- SET sSendBack='----';
-- -- SET sOutVar='----'; -- ran out of space. Think up something else. This was your idea, afterall :p
-- -- we will drop out of routine
-- END IF;
IF num_to_use<1679616 THEN
-- I don't feel like doing a LOOP for the below
-- Honestly just because I am tired at the moment.
SET i2=num_to_use;
SET i1=FLOOR(i2/46656); -- 46656 is 36 cubed
IF i1 between 0 and 9 THEN
SET sSendBack=CHAR(48+i1);
ELSE
SET sSendBack=CHAR(65+i1-10);
END IF;
SET i2=i2-(i1*46656);
SET i1=FLOOR(i2/1296); -- 1296 is 36 squared
IF i1 between 0 and 9 THEN
SET sSendBack=CONCAT(sSendBack,CHAR(48+i1));
ELSE
SET sSendBack=CONCAT(sSendBack,CHAR(65+i1-10));
END IF;
SET i2=i2-(i1*1296);
SET i1=FLOOR(i2/36); -- 36 is 36 to the first power
IF i1 between 0 and 9 THEN
SET sSendBack=CONCAT(sSendBack,CHAR(48+i1));
ELSE
SET sSendBack=CONCAT(sSendBack,CHAR(65+i1-10));
END IF;
SET i2=i2-(i1*36);
SET i1=FLOOR(i2/1); -- 1 is 36 to the 0th
IF i1 between 0 and 9 THEN
SET sSendBack=CONCAT(sSendBack,CHAR(48+i1));
ELSE
SET sSendBack=CONCAT(sSendBack,CHAR(65+i1-10));
END IF;
SET sOutVar=sSendBack; -- base36 number (a string) to OUT parameter
SELECT num_to_use,sOutVar as yourNumber; -- send out as a resultset too
ELSE
SET sSendBack='----';
SET sOutVar=sSendBack; -- base36 number (a string) to OUT parameter
select num_to_use,sOutVar as yourNumber; -- send out as a resultset too
END IF;
END;$$
DELIMITER ;
这里有一个你可能会感兴趣的例行公事。其概念是为各种序列(在系统范围内使用)提供一个控制表。简言之,以下是一个卑鄙的人。它使用MySQL“意向锁” 您需要的是
Base36
数字功能,这就提供了其中的一部分。如何将其嵌入到设置中,如果您这样做,则取决于您
控制表:
-- drop table if exists sequences;
create table sequences
( -- the numbers in here are the next numbers free to use
-- so it is yours once you acquire the INTENTION lock
-- but do an UPDATE for the next guy by incrementing the number
-- and COMMIT
id int auto_increment primary key,
sectionType varchar(200) not null,
nextSequence int not null,
unique key(sectionType) -- perhaps overkill on index but meh
);
-- truncate table sequences;
insert sequences (sectionType,nextSequence) values
('Chassis Serial Number',1),('Engine Block Serial Number',1),('base36number',0);
存储过程:
DROP PROCEDURE IF EXISTS getBase36;
DELIMITER $$CREATE PROCEDURE getBase36
( OUT sOutVar CHAR(4) -- out parameter for base36 number
)
BEGIN
DECLARE num_to_use INT;
DECLARE i1,i2 INT;
DECLARE sSendBack CHAR(4);
-- 0-9 is ascii 48 to 57
-- A-Z is ascii 65 to 90
-- 0000 to ZZZZ in that order. 0 to 9 then A etc 36 positions
-- first char is 0. 36th char is Z. Base36, 0 is 0000 , 35 is 000Z, 36 is 00010
-- 1.68M possibilities
-- output ranges from 0000 to ZZZZ
START TRANSACTION;
SELECT nextSequence into num_to_use from sequences where sectionType='base36number' FOR UPDATE;
UPDATE sequences set nextSequence=nextSequence+1 where sectionType='base36number';
COMMIT; -- because of this, it cannot be a FUNCTION but must be a stored proc, else error 1422
-- which is Error 1422: Explicit or implicit commit is not allowed in a stored function or trigger
SET sOutVar='';
-- IF num_to_use>1679616 THEN
-- SET sSendBack='----';
-- -- SET sOutVar='----'; -- ran out of space. Think up something else. This was your idea, afterall :p
-- -- we will drop out of routine
-- END IF;
IF num_to_use<1679616 THEN
-- I don't feel like doing a LOOP for the below
-- Honestly just because I am tired at the moment.
SET i2=num_to_use;
SET i1=FLOOR(i2/46656); -- 46656 is 36 cubed
IF i1 between 0 and 9 THEN
SET sSendBack=CHAR(48+i1);
ELSE
SET sSendBack=CHAR(65+i1-10);
END IF;
SET i2=i2-(i1*46656);
SET i1=FLOOR(i2/1296); -- 1296 is 36 squared
IF i1 between 0 and 9 THEN
SET sSendBack=CONCAT(sSendBack,CHAR(48+i1));
ELSE
SET sSendBack=CONCAT(sSendBack,CHAR(65+i1-10));
END IF;
SET i2=i2-(i1*1296);
SET i1=FLOOR(i2/36); -- 36 is 36 to the first power
IF i1 between 0 and 9 THEN
SET sSendBack=CONCAT(sSendBack,CHAR(48+i1));
ELSE
SET sSendBack=CONCAT(sSendBack,CHAR(65+i1-10));
END IF;
SET i2=i2-(i1*36);
SET i1=FLOOR(i2/1); -- 1 is 36 to the 0th
IF i1 between 0 and 9 THEN
SET sSendBack=CONCAT(sSendBack,CHAR(48+i1));
ELSE
SET sSendBack=CONCAT(sSendBack,CHAR(65+i1-10));
END IF;
SET sOutVar=sSendBack; -- base36 number (a string) to OUT parameter
SELECT num_to_use,sOutVar as yourNumber; -- send out as a resultset too
ELSE
SET sSendBack='----';
SET sOutVar=sSendBack; -- base36 number (a string) to OUT parameter
select num_to_use,sOutVar as yourNumber; -- send out as a resultset too
END IF;
END;$$
DELIMITER ;
如果你需要它是唯一的,我不会让它是随机的,特别是只有4个字符。我只需要一个普通的序列,你可以将它转换成基数36,比如(你可以把基数62的小写字母加进去)。我不确定是否可以从MySQL中的触发器调用函数。是否需要大小写字母?让代码只由数字和大写字母组成行吗?我需要生成一个具有一定可伸缩性的小“散列”以供一千或一百万用户使用(如果可能的话..只是为了不需要进行将来的维护)。。但是会被老年用户使用,所以我想做一些尽可能小的东西。Base32可能就足够了:1.048.575=vvv~so。。如何授予哈希唯一性*我想进行(1048575-USER_ID)转换,但会为初始用户生成最简单的ID,如“VVVE”、“VVUA”。。有什么想法可以随机化并成为唯一的值吗?如果你需要它是唯一的,我不会让它是随机的,特别是只有4个字符。我只需要一个普通的序列,你可以将它转换成基数36,比如(你可以把基数62的小写字母加进去)。我不确定是否可以从MySQL中的触发器调用函数。是否需要大小写字母?让代码只由数字和大写字母组成行吗?我需要生成一个具有一定可伸缩性的小“散列”以供一千或一百万用户使用(如果可能的话..只是为了不需要进行将来的维护)。。但是会被老年用户使用,所以我想做一些尽可能小的东西。Base32可能就足够了:1.048.575=vvv~so。。如何授予哈希唯一性*我想进行(1048575-USER_ID)转换,但会为初始用户生成最简单的ID,如“VVVE”、“VVUA”。。是否有随机化和唯一化的想法?