データベースの制約の1つに一意制約(UNIQUE)があり、一意制約(UNIQUE)を設定した列では、重複したデータを追加することができない。ただ、NULL値については、データベースの種類によっては、一意制約(UNIQUE)を設定した列でも複数のデータを追加できる。
今回は、Oracle・MySQL・PostgreSQL・SQL Serverの各DB上で、一意制約(UNIQUE)の挙動を確認してみたので、その結果を共有する。
前提条件
Oracle XEのインストールが完了していること。
また、下記記事に記載されている、MySQLとPostgreSQLでのユーザー作成とUSER_DATAテーブル作成が完了していること。


さらに、下記記事の「前提条件」の内容が完了していること。

やってみたこと
Oracleの場合の実行結果
Oracleの場合の実行結果は以下の通りで、一意制約(UNIQUE)を設定した列でも、NULL値のデータは複数追加できる。
1) 検証用のemployeeテーブルを追加する。列「name」に一意制約(UNIQUE)を設定している。
create table employee ( emp_id integer primary key not null , name varchar2(40) , constraint uq_name unique(name) )

2) 検証用のemployeeテーブルに、検証用のデータを追加する。
insert into employee values (1, 'テスト プリン1'); insert into employee values (2, ' '); insert into employee values (3, null); commit;

3) 検証用のemployeeテーブルのデータの中身は、以下の通り。
select * from employee order by emp_id

4) 一意制約(UNIQUE)を設定した列「name」にNULL・空文字以外の重複データを追加すると、一意制約エラーになることが確認できる。
insert into employee values (4, 'テスト プリン1')

5) 一意制約(UNIQUE)を設定した列「name」に空文字の重複データを追加すると、一意制約エラーになることが確認できる。
insert into employee values (4, ' ')

6) 一意制約(UNIQUE)を設定した列「name」にNULL値の重複データを追加すると、正常にデータを追加できることが確認できる。
insert into employee values (4, null)

7) コミットして検証用のemployeeテーブルのデータの中身を確認すると、以下のように、NULL値の重複データが含まれていることが確認できる。
commit

select * from employee order by emp_id


MySQLの場合の実行結果
MySQLの場合の実行結果は以下の通りで、一意制約(UNIQUE)を設定した列でも、NULL値のデータは複数追加できる。
1) 検証用のemployeeテーブルを追加する。列「name」に一意制約(UNIQUE)を設定している。
create table employee ( emp_id int primary key not null , name varchar(40) , constraint uq_name unique(name) )

2) 検証用のemployeeテーブルに、検証用のデータを追加する。
insert into employee values (1, 'テスト プリン1'); insert into employee values (2, ' '); insert into employee values (3, null); commit;

3) 検証用のemployeeテーブルのデータの中身は、以下の通り。
select * from employee order by emp_id

4) 一意制約(UNIQUE)を設定した列「name」にNULL・空文字以外の重複データを追加すると、一意制約エラーになることが確認できる。
insert into employee values (4, 'テスト プリン1')

5) 一意制約(UNIQUE)を設定した列「name」に空文字の重複データを追加すると、一意制約エラーになることが確認できる。
insert into employee values (4, ' ')

6) 一意制約(UNIQUE)を設定した列「name」にNULL値の重複データを追加すると、正常にデータを追加できることが確認できる。
insert into employee values (4, null)

7) コミットして検証用のemployeeテーブルのデータの中身を確認すると、以下のように、NULL値の重複データが含まれていることが確認できる。
commit

select * from employee order by emp_id


PostgreSQLの場合の実行結果
PostgreSQLの場合の実行結果は以下の通りで、一意制約(UNIQUE)を設定した列でも、NULL値のデータは複数追加できる。
1) 検証用のemployeeテーブルを追加する。列「name」に一意制約(UNIQUE)を設定している。
create table employee ( emp_id integer primary key not null , name varchar(40) , constraint uq_name unique(name) )

2) 検証用のemployeeテーブルに、検証用のデータを追加する。
insert into employee values (1, 'テスト プリン1'); insert into employee values (2, ' '); insert into employee values (3, null);

3) 検証用のemployeeテーブルのデータの中身は、以下の通り。
select * from employee order by emp_id

4) 一意制約(UNIQUE)を設定した列「name」にNULL・空文字以外の重複データを追加すると、一意制約エラーになることが確認できる。
insert into employee values (4, 'テスト プリン1')

5) 一意制約(UNIQUE)を設定した列「name」に空文字の重複データを追加すると、一意制約エラーになることが確認できる。
insert into employee values (4, ' ')

6) 一意制約(UNIQUE)を設定した列「name」にNULL値の重複データを追加すると、正常にデータを追加できることが確認できる。
insert into employee values (4, null)

7) 検証用のemployeeテーブルのデータの中身を確認すると、以下のように、NULL値の重複データが含まれていることが確認できる。
select * from employee order by emp_id


SQL Serverの場合の実行結果
SQL Serverの場合の実行結果は以下の通りで、一意制約(UNIQUE)を設定した列でも、NULL値のデータは複数追加できる。
1) 検証用のemployeeテーブルを追加する。列「name」に一意制約(UNIQUE)を設定している。
create table dbo.employee ( emp_id int primary key not null , name nvarchar(40) , constraint uq_name unique(name) )

2) 検証用のemployeeテーブルに、検証用のデータを追加する。
insert into dbo.employee values (1, 'テスト プリン1'); insert into dbo.employee values (2, ' '); insert into dbo.employee values (3, null);

3) 検証用のemployeeテーブルのデータの中身は、以下の通り。
select * from dbo.employee order by emp_id

4) 一意制約(UNIQUE)を設定した列「name」にNULL・空文字以外の重複データを追加すると、一意制約エラーになることが確認できる。
insert into dbo.employee values (4, 'テスト プリン1')

5) 一意制約(UNIQUE)を設定した列「name」に空文字の重複データを追加すると、一意制約エラーになることが確認できる。
insert into dbo.employee values (4, ' ')

6) 一意制約(UNIQUE)を設定した列「name」にNULL値の重複データを追加すると、他のDBとは違い、一意制約エラーになることが確認できる。
insert into dbo.employee values (4, null)

なお、NULL値の重複データを追加してもエラーにならないように一意制約を設定する方法については、以下の記事を参照のこと。

要点まとめ
- データベースの制約の1つに一意制約(UNIQUE)があり、一意制約(UNIQUE)を設定した列では、重複したデータを追加することができない。
- Oracle・MySQL・PostgreSQLの場合は、一意制約(UNIQUE)を設定した列でもNULL値の重複データは複数追加でき、SQL Serverの場合は、一意制約(UNIQUE)を設定した列にNULL値の重複データは複数追加できない違いがある。