Jun 28, 2006

Generate Unique User IDs

This requirement was actually a question in the discussion forum. I thought I will keep a copy of my solution here for reference.

Okay, so here it goes.

I am taking the narration from the actual post (thanks to him), with a few changes.

Lets say I have a table like this.

create table User_Master
(
id int identity(1,1) primary key,
FirstName varchar(50),
LastName varchar(50),
username varchar(100)
)


I want to create some unique entries for username – I don’t want to touch the username that already has a value. But I need to update the username for which the current value is ‘’.

Rules for creation of the username value for update:

Try creating the username as the first 2 letters of FirstName and first 2 letters of LastName.
If the username exists in the database then the create with first 3 letters of FirstName and first 3 letters of LastName
If the username exists in the database then the create with first 4 letters of FirstName and first 4 letters of LastName.
This should go on till I get a unique value.

Examples:
Michael Bach -----> miba
Franz Mueller -----> frmu

Now say I have a name
Franziska Mueller -----> framue ( Since frmu already exist)

Let me put in some data into the table

insert into User_Master (FirstName,LastName,username) values('Michael','Bach','')
insert into User_Master (FirstName,LastName,username) values('Franz','Mueller','')
insert into User_Master (FirstName,LastName,username) values('Franziska','Mueller','')


Now we have set up the scenario. We need to generate the username.
For this I will be using Temp table to hold numbers from 1 to 50.
This is for selecting upto 50 characters in the FirstName and LastName and search with the existing usernames. You can tune it to meet your purpose.

This is the temp table I use. I am using the seed as 2 since I need to start from 2 letters from first and the last name for my username.

select top 50 identity(int,2,1) as id into #temp from sysobjects

Now I cannot do a batch update to my table, since The old value should be updated when i search for existence.

This is how I do it. I will loop through and search for the rows which has username =''.
Take the first row that has username = ''. And then update the username. I will keep doing this till there are no more rows that has username = ''

declare @a int
declare @rowcount int
select @a = min(id) from User_Master where username = ''
set @rowcount = @@rowcount


while(@rowcount > 0)
begin
update a
set username = (select top 1 left(a.firstname,b.id) + left(a.lastname,b.id)

from #temp b
where not exists

(
select 1 from User_Master c
where c.username =left(a.firstname,b.id) + left(a.lastname,b.id)
)
order by b.id
)
from

User_Master a
where

a.id = @a

set @rowcount = @@rowcount
select @a = min(id) from User_Master where username = '' and id> @a
end



The logic above is quite straightforward except for this snippet used set the username

select top 1 left(a.firstname,b.id) + left(a.lastname,b.id)
from #temp b where not exists
(
select 1 from User_Master c
where c.username =left(a.firstname,b.id) + left(a.lastname,b.id)
)

order by b.id

What I try to do here is take the firstname and lastname of the current row to be updated and join it with the temp table and get all possible usernames (2 char from first and 2 from last name, 3 chars, 4 chars, ..... upto 50 chars and get the first username that does not exist in the User_Master and use it to update the user name.


Now try this.

select * from User_Master

Here is the result

id FirstName LastName username
---- ---------- --------- ---------
1 Michael Bach MiBa
2 Franz Mueller FrMu
3 Franziska Mueller FraMue


-----------------------------------------------------------------------------------------------------

I should thank Erland for his article on arrays in SQL Server. If you have questions on why I used the #temp table and how that join worked, you will find the answers here.

http://www.sommarskog.se/arrays-in-sql.html

Rest assured, its worth every minute you spend on this.

3 comments:

  1. Hi Omnibuzz,
    This is great but my request is ont the same line but a little different i am trying to modify but not successfull.


    Here is my requirement.I have been trying various things but i am not successfull till this point

    Here is an example
    LastName Fname Uname
    Smith Jo Smith
    Smith Jo SmithJ
    Smith Jo Smithjo
    smith Jo smitj
    smith Jo smitjo
    smith Jo smij
    smith Jo smijo

    Basically Username should not be greater than 7 and and can be just the lastname if that username doesn't exist and also ,if greater than 7 just take first 7 chars

    if lastname already exists we have take one char from firstname and then goes on as outlined in the example


    Any suggestions would be greatly appreciated.


    Thanks,

    ReplyDelete
  2. Check this out...
    data:

    create table User_Master
    (
    id int identity(1,1) primary key,
    FirstName varchar(50),
    LastName varchar(50),
    username varchar(100)
    )

    insert into User_Master (FirstName,LastName,username) values('Michael','Bach','')
    insert into User_Master (FirstName,LastName,username) values('Franz','Mueller','')
    insert into User_Master (FirstName,LastName,username) values('Franziska','Mueller','')
    insert into User_Master (FirstName,LastName,username) values('Jo','Smith','')
    insert into User_Master (FirstName,LastName,username) values('Jo','Smith','')
    insert into User_Master (FirstName,LastName,username) values('Jo','Smith','')
    insert into User_Master (FirstName,LastName,username) values('Jo','Smith','')
    insert into User_Master (FirstName,LastName,username) values('Jo','Smith','')
    insert into User_Master (FirstName,LastName,username) values('Jo','Smith','')


    And the query

    -- Starts here

    select top 50 identity(int,0,1) as id into #temp from sysobjects

    declare @a int
    declare @rowcount int
    select @a = min(id) from User_Master where username = ''
    set @rowcount = @@rowcount

    while(@rowcount > 0)
    begin
    update a
    set username = (select top 1 left(left(a.lastname,len(lastname) - b.id) + left(a.FirstName,d.id),7)
    from #temp b, #temp d
    where not exists
    (
    select 1 from User_Master c
    where c.username =left(left(a.lastname,len(lastname) - b.id) + left(a.FirstName,d.id),7)
    )
    and len(lastname) > b.id
    and not(b.id >=1 and d.id = 0)
    order by b.id,d.id
    )
    from
    User_Master a
    where
    a.id = @a

    set @rowcount = @@rowcount
    select @a = min(id) from User_Master where username = '' and id> @a
    end

    drop table #temp

    -- Ends here

    -Omni

    ReplyDelete
  3. Hi Omnibuzz,
    Thanks for the information above.

    I too am looking to generate usernames using SQL, though the format I am looking for, is slightly different.


    Here is my requirement - If a username exists, the system should append a number at the end of the username, such that the username is unique.

    For example -
    LN FN Username Display Name
    Smith John JSmith John Smith
    Smith John JSmith1 John Smith 1
    Smith Jack JSmith2 Jack Smith

    Basically Username should not be greater than 10 characters.
    Any suggestions would be greatly appreciated.

    - Madan

    ReplyDelete