Unique index that ignores null values

I have a table in which there is a field called UserName. This field is not the primary key but it needs to be a unique key. This value is often left as null.

I built a unique index on that field but I had to remove it because null values are seen as duplicates. Is there a way to enforce uniqueness only if the value is not null.
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.

You could write a trigger that checks for a duplicate value upon insert or update and then deletes the duplicate entry.
moonriseAuthor Commented:
I was hoping for some kind of flag to ignore null values. Oracle does no treat null values as duplicates.

Also, there is no "before insert" trigger so should the trigger issue a rollback?

Finally, I am also considering never leaving the value NULL - possibly by using a DEFAULT constraint. But I would need a default constraint on field1 that set it to whatever value field 2 has. Is that possible or does the default have to be a constant?

Thank you.
Gustavo Perez BuenrostroCommented:
You must create a unique constraint if you need to enforce uniqueness of column UserName. However, This can be done if there are any duplicate values. Because of  UserName column is nullable, you have a lot of null values previously stored in it.

To resolve your problem, do the following:

1] Replace all null values with a unique value (I suggest GUID).
2] Create a UNIQUE constraint on column UserName.
3] Create a trigger to replace Null value on UserName column with GUID.

Check next code and let me know if works for you.

-- 1] Replace all null values with a
--    unique value.

declare cr_User cursor local
    for select UserName
          from Users
         where Username
               is null
open cr_User

while 1=1
    fetch cr_User
    if @@fetch_status<>0 break
    update Users
       set UserName
           =cast(newid() as varchar(36))
     where current of cr_User

-- 2] Create a UNIQUE constraint on
--    column UserName

alter table users add constraint UQN_UserName unique (UserName)

-- 3] Create a trigger to replace Null
--    value on UserName column with
--    GUID.

create trigger TG_Users on Users
for insert,update
  update Users
     set UserName
        =cast(newid() as varchar(36))
    from Inserted
   where Users.UserId

PD: You don’t mention anything about your table’s structure so I assume UserName is varchar datatype column with at least 36-character length.

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
Yes the trigger can rollback before it posts the record.  I don't think you can set a default value to equal the value of another field.  But, you could do this with a trigger also.
moonriseAuthor Commented:
Thank you. It looks like this will work.
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
Microsoft SQL Server

From novice to tech pro — start learning today.