Generate Unique serial numbers

I'm looking for a way to generate unique serial numbers like you would find on a software product..

i have a few requirements.

1) the number needs to be generated on the fly
2) it must be unique on the host machine, if it can be globally unique even better
3) it should contain only the charachters "123456789ABCDEFGHJKLMNPQRSTUWXYZ", so as to avoid mis-typing them
4) the key should be no more than 20 characters long, and always the same length
5) serial numbers will be validated against the DB, so it does not require a checksum

So far i've experimented with hashing uuid's and trying to convert them to different base systems, but i'm not sure whether the results i'm creating are still unique.

i'm happy to create the keys using cfscript or in a java object that i can instantiate in my CF code

any ideas..

Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Have you thought about using CreateUUID

It has only hex digits ( 0 throgh 9 and A through F)

But it is 35 characters long

Otherwise it meets all of your requirements.  

Maybe you could use 35 characters or somehow use only a portion of the generated value (although I don't know what unique constraints you would hit that way.

Maybe you could use the 1st 20 chars and do a test to see if it is already in the DB - if so then generate a new one.  Chances are that you will not incurr this penalty too often...


Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
monkeychumpAuthor Commented:
i don't want to use a plain uuid, because there values look vaguely sequential, and it is essential that this key cannot just be guessed.

I have MD5 hashed a uuid which gives a 32 character hex string, which is more "random" in its appearance, but what i was hoping to do was shorten that to 20 characters (with a larger caracter set), but retain its uniqueness..

Does the validating DB contain all generated serial numbers? If so, you could do something like this (in pseudo code):

generated_code = generate 20 char code using "0-9A-Z"
while (select codecolumn from table where codecolumn = generated_code)

The following code will generate 20-char ID with very high probability of uniqueness:

<cfset a=Replace(CreateUUID(), "-", "", "ALL")>
<cfset str="">
<cfloop index="i" from="1" to="4">
   <cfset b=InputBaseN(Left(a, 8), 16)>
   <cfif b LT 0>
      <cfset b=-b>
   <cfset a=RemoveChars(a, 1, 8)>
   <cfloop index="j" from="1" to="5">
      <cfset c=b MOD 35>
      <cfset b=b/35>
      <cfset str=str & Mid(set, c+1, 1)>
   <cfset str=str & "-">
<cfset str=Left(str, 23)>

Or try this.  I am doing something similar but for a much shorter string for generating security passwords.

function getRandString(stringLength,spacerlength) {
      var tempAlphaList = "a,b,c,d,e,g,h,i,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z";
      var tempNumList = "1,2,3,4,5,6,7,8,9,0";
      var tempCompositeList = tempAlphaList&""&tempNumList;
      var tempCharsInList = listLen(tempCompositeList,",");
      var tempCounter = 1;
      var tempWorkingString = "";
      //loop from 1 to stringLength to generate string
      while (tempCounter LTE stringLength+spacerlength) {
            if ((tempCounter mod spacerlength is 0) and (tempCounter LT stringLength+spacerlength)){
                  tempWorkingString = tempWorkingString&"-";}
            else if (tempCounter LT stringLength+spacerlength) {
                  tempWorkingString = tempWorkingString&listGetAt(tempCompositeList,randRange(1,tempCharsInList),",");
            tempCounter = tempCounter + 1;
      return tempWorkingString;

cfset licensenum = ucase(getRandString(20,5))#

Query your table for  licensenum, if it exists then loop til recordcount is 0.

Also just changed the number values to change the length of the string and the position of the -
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Web Servers

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.