以下是您可能在某個時間感興趣的例程。這個概念是你有一個控制表的各種序列(全系統使用)。總之,以下是一名Base36稻草人。它使用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 ;
測試:
set @f='';
CALL getBase36(@f); -- initial time for 0000
CALL getBase36(@f); -- 1 is 0001
CALL getBase36(@f); -- 2 is 0002
-- now start testing Boundary conditions
-- pretend we have an INTENTION lock on table and just do an update to test quicker
UPDATE sequences set nextSequence=34 where sectionType='base36number';
CALL getBase36(@f); -- 34 is 000Y
CALL getBase36(@f); -- 35 is 000Z
CALL getBase36(@f); -- 36 is 0010
UPDATE sequences set nextSequence=12345 where sectionType='base36number';
CALL getBase36(@f); -- 12345 is 09IX =9*36*36+18*36+33
select 9*36*36+18*36+33;
-- = 12345
UPDATE sequences set nextSequence=1679614 where sectionType='base36number';
CALL getBase36(@f); -- 1679614 is ZZZY
CALL getBase36(@f); -- 1679615 is ZZZZ
CALL getBase36(@f); -- 1679616 is ----
CALL getBase36(@f); -- 1679617 is ----
-- so after 1679615 you can't use your numbering scheme anymore (or my scheme)
-- but in either case, this is the range of numbers you chose to implement
-- up to 1.68M (roughly)
如果你需要它是獨一無二的,我不會讓它是隨機的,尤其是與只有4個字符。我只需要將一個正常的序列轉換爲Base 36,例如http://forums.mysql.com/read.php?98,77546,98265#msg-98265(您可以在Base 62的小寫字母中添加) 。我不確定您是否可以從MySQL中的觸發器調用函數。 – topshot
你需要大寫*還是小寫字母?只有數字和大寫字母的代碼才能正常工作? – Bohemian
我需要爲一千或一百萬用戶生成一些「散列」,並提供一些可擴展性(如果可能的話......只是不需要做一個未來的維護)..但是會被老年用戶使用,所以我想讓儘可能最小的東西。 –