1

I have a request as part of an application I am working on to generate a UserId with the following criteria:

  1. It will have a set 4 digit prefix
  2. The next 10 digits will be random
  3. A check-digit will be added on the end

Points 1 and 3 are straight-forward, but what would the best way be to generate a 10 digit random number whilst ensuring that it hasn't already been used.

I don't particularly like the idea of choosing one randomly, seeing if it has been taken and then either accepting or trying again.

My other thought was to generate a list of X numbers in advance (X being a number greater than the number of accounts you expect to be created) and just take the next one off the list as the accounts are created.

Any thoughts?

EDIT: Lets bring technology into this. If I am using a SQL server database, is there a way I can make the database do this for me? E.g. enforce a unique constraint and get the database to generate the number?

Neil
  • 2,659
  • 7
  • 35
  • 57
  • 3
    The only way to be 100% sure there is no other userid with the same random digits is to compare the gernerated to **all** existing users. – Sebastian Schneider Oct 16 '15 at 08:12
  • 1
    ... which you can do preemptively (as OP suggests) or at creation (as OP dislikes), but you have to do it *sometime*. – Amadan Oct 16 '15 at 08:13
  • "Lets bring technology into this." Enforcing a unique constraint is easy, just slap a `UNIQUE` index on the column; so you don't need a `SELECT`, just `INSERT` and generate another one if `INSERT` fails. Having the database generate it is a no-go unless you make a stored procedure that will do the same thing, or you use `uniqueidentifier` to make a GUID (which is not 10 digits, but `xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`). – Amadan Oct 16 '15 at 09:23

3 Answers3

2

Encryption. See this answer.

What you need is basically encrypt a sequential ID, thus producing a seemingly random number.

What's especially good about this is that you can do this all client-side, albeit in two consecutive transactions.

Community
  • 1
  • 1
Anton Gogolev
  • 113,561
  • 39
  • 200
  • 288
  • If you change "random" into "seemingly random", this is a good idea; any sufficiently opaque bijective method should do. Finding a bijection that generates precisely 10 digits is a bit of a challenge; OP should judge how tight his #2 requirement is. – Amadan Oct 16 '15 at 09:15
  • @Amadan You can always pad with zeroes and get precisely 10 digits. – Anton Gogolev Oct 16 '15 at 09:21
  • You are right, in case of a 32-bit output, you will always have up to 10 digits. – Amadan Oct 16 '15 at 09:25
  • This is also interesting: http://preshing.com/20121224/how-to-generate-a-sequence-of-unique-random-integers/ – Neil Oct 16 '15 at 13:11
0

The only way to be 100% sure there is no other userid with the same random digits is to compare the gernerated to all existing users, you have to do it sometime

The only possibility is to do this code-side.

BUT you can save the random generated id to the userdatabase and compare this with your new key (in your code)

e.g. SELECT * FROM xy WHERE userid = 'newuserid'

If the result is null your key never was generated.

Sebastian Schneider
  • 4,896
  • 3
  • 20
  • 47
0

Thanks to Anton's answer I found this C# implementation of the skip32 encryption algorithm.

https://github.com/eleven41/Eleven41.Skip32

Using this I can pass in an incrementing database identity integer and get a nice random looking 9/10 digit number from it. So a simple call like

int result = cipher.Encrypt(databaseIdentity);

will give me the number I want. No need for duplicate checking as each will be unique.

Neil
  • 2,659
  • 7
  • 35
  • 57