Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I create a unique index in Oracle but ignore nulls?

Tags:

sql

oracle

ddl

I am trying to create a unique constraint on two fields in a table. However, there is a high likelihood that one will be null. I only require that they be unique if both are not null (name will never be null).

create unique index "name_and_email" on user(name, email); 

Ignore the semantics of the table and field names and whether that makes sense - I just made some up.

Is there a way to create a unique constraint on these fields that will enforce uniqueness for two not null values, but ignore if there are multiple entries where name is not null and email is null?

This question is for SQL Server, and I'm hoping that the answer is not the same: How do I create a unique constraint that also allows nulls?

like image 954
Brian Ramsay Avatar asked Sep 03 '09 17:09

Brian Ramsay


People also ask

Does unique index allow NULL in Oracle?

If a field is defined as NOT NULL, it will not allow you to insert a null value into that field. Are you sure you inserted a null value or did you just insert a space? We do not use nulls in our shop.

Does unique index allow NULL?

Therefore, unique indexes do not enforce primary key constraints by themselves because they allow null values.

Can unique key have multiple nulls?

There are way to create a unique index that allows multiple nulls in MS SQL Server, but it's not the default. The default in MS is to allow just one NULL. But that's not the ANSI standard. ANSI standards 92, 99, and 03 explicitly allow multiple nulls with unique.

Why does unique key allow NULL?

Solution 1 Logically, any key which is allowed to contain non duplicate (unique) values is a unique key, NULL is a permissible value in sql server , so it can have NULL for a single time just like any other value.


2 Answers

I don't know how many people still get directed to this answer, but at least in the latest version of oracle, you're allowed to have multiple rows with null on a unique index and the accepted answer isn't necessary

like image 23
broll Avatar answered Sep 20 '22 17:09

broll


We can do this with a function-based index. The following makes use of NVL2() which, as you know, returns one value if the expression is not null and a different value if it is null. You could use CASE() instead.

SQL> create table blah (name varchar2(10), email varchar2(20))   2  /  Table created.  SQL> create unique index blah_uidx on blah   2      (nvl2(email, name, null), nvl2(name, email, null))   3  /  Index created.  SQL> insert into blah values ('APC', null)   2  /  1 row created.  SQL> insert into blah values ('APC', null)   2  /  1 row created.  SQL> insert into blah values (null, '[email protected]')   2  /  1 row created.  SQL> insert into blah values (null, '[email protected]')   2  /  1 row created.  SQL> insert into blah values ('APC', '[email protected]')   2  /  1 row created.  SQL> insert into blah values ('APC', '[email protected]')   2  / insert into blah values ('APC', '[email protected]') * ERROR at line 1: ORA-00001: unique constraint (APC.BLAH_UIDX) violated   SQL> 

Edit

Because in your scenario name will always be populated you will only need an index like this:

SQL> create unique index blah_uidx on blah   2      (nvl2(email, name, null), email)   3  /  Index created.  SQL>  
like image 146
APC Avatar answered Sep 22 '22 17:09

APC