web-dev-qa-db-ja.com

Oracleで一意のインデックスを作成してnullを無視するにはどうすればよいですか?

テーブルの2つのフィールドに一意の制約を作成しようとしています。ただし、1つがnullになる可能性が高くなります。両方がnullでない場合のみ、それらが一意であることを要求します(nameがnullになることはありません)。

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

テーブル名とフィールド名のセマンティクスを無視し、それが理にかなっているかどうかを確認しました。

これらのフィールドにnullでない2つの値の一意性を強制する一意の制約を作成する方法はありますが、nameがnullでなく、emailがnullである複数のエントリがある場合は無視しますか?

この質問はSQL Serverに対するものであり、答えが同じではないことを願っています: nullも許可する一意の制約を作成するにはどうすればよいですか?

24
Brian Ramsay

これは、関数ベースのインデックスで実行できます。以下はNVL2()を利用しています。これは、ご存じのとおり、式がnullでない場合は1つの値を返し、nullの場合は別の値を返します。代わりにCASE()を使用できます。

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>

編集

シナリオでは常に名前が入力されるため、次のようなインデックスのみが必要になります。

SQL> create unique index blah_uidx on blah
  2      (nvl2(email, name, null), email)
  3  /

Index created.

SQL> 
35
APC

この回答がまだいくつあるかはわかりませんが、少なくとも最新バージョンのOracleでは、一意のインデックスにnullを含む複数の行を含めることができ、承認された回答は必要ありません。

2
broll