ablog

不器用で落着きのない技術者のメモ

Oracle でユニークインデックスを作ってみる

ユニークインデックスを作成して

create unique index scott.emp_ename_idx on scott.emp (ename);

確認して、

set pagesize 10000
set linesize 130
col table_name for a10
col index_name for a20
col column_name for a10
col column_position for 9999
select index_name, table_name, column_name, column_position 
	from user_ind_columns 
		where table_name = 'EMP'
		order by index_name, column_position;

INDEX_NAME           TABLE_NAME COLUMN_NAM COLUMN_POSITION
-------------------- ---------- ---------- ---------------
EMP_ENAME_IDX        EMP        ENAME                    1
PK_EMP               EMP        EMPNO                    1

表にはこんなデータが入っているので、

select empno,ename from emp;

     EMPNO ENAME
---------- ----------
      7369 SMITH
      7499 ALLEN
      7521 WARD
      7566 JONES
      7654 MARTIN
      7698 BLAKE
      7782 CLARK
      7788 SCOTT
      7839 KING
      7844 TURNER
      7876 ADAMS
      7900 JAMES
      7902 FORD
      7934 MILLER
        15 NEO

ename が重複するよう insert してみると、

insert into emp(empno, ename) values(16, 'NEO');

*
ERROR at line 1:
ORA-00001: unique constraint (SCOTT.EMP_ENAME_IDX) violated

先ほどユニークインデックスを作ったので、一意制約違反になる。


ところで、プライマリキーと NOT NULL 制約をつけたユニークインデックスって何が違うんだろうって思ったんだけど、

プライマリキーとユニークキーの違い

プライマリキーとユニークキーの違いは確実に 識別する(identification) ための主たる制約と NULL 以外の行が 一意であること(uniqueness) を保証する目的のためのその他の制約という違いがある。
さらに原則的にキーの値を変更を許可するかしないかという面もある。 人間にとっては意味論的に異なるものであるが Oracle データベースにしてみれば、その内部の仕組みに大きな差はない。

例としては、ある顧客を会員番号を主キーとして管理している場合に (本籍)住所、氏名、生年月日のカラムの組み合わせが一意キーとして考えられる。
通常、この組み合わせのキーは一意である*1が変更可能であることに大きな違いがある。そして、これらの組み合わせを使ったテーブルのリレーションは好ましいものではない。
一方、主キー(会員番号)は退会処理などを特別な処理しない限りは変更されることはない。不可能ではないが原則、変更不可能という位置づけである。

整合性制約 - オラクル・Oracleをマスターするための基本と仕組み

プライマリキーはキー値の変更を許可しないってことか。
たしか、DB2ってプライマリキーってなかった気がする。テーブル定義書でプライマリキーになっているところはDDLを見ると、ユニークインデックス + NOT NULL 制約になっていたような。


追記(2009/09/04):
IBM の sin さん(Unofficial DB2 BLOG)にツッコミを頂きました。

>DB2にも明確にプライマリーキー(PK)という機能はありますよ。

Oracle でユニークインデックスを作ってみる - ablog

失礼しました。

主キー制約は、主キーを構成する列または列の組み合わせに含まれるすべての値がユニーク(固有)であることを保証します。主キーは、表内の特定の行を識別するために使われます。主キーは1つの表に1つしか設定できませんが、ユニーク・キーは複数設定できます。主キー制約はユニーク制約の特別な場合で、1次索引を使って強制されます。

IBM Developer 日本語版 : 大変申し訳ありません。このページは無効です。

ほんとうですね。
違いは、

  • 「主キーは1つの表に1つしか設定できません」
  • 「1次索引を使って強制されます」

の2点みたい。1次索引ってなんだろ?

>OracleにしてもDB2にしてもPKが変更不可ってことは無いんじゃないでしょうか。

Oracle でユニークインデックスを作ってみる - ablog

これは試してみたら、sim さんのおっしゃる通りだった。

SQL> set pagesize 10000
set linesize 130
col table_name for a10
col index_name for a20
col column_name for a10
col column_position for 9999
select index_name, table_name, column_name, column_position
        from user_ind_columns
                where table_name = 'EMP'
                order by index_name, column_position;
SQL> SQL> SQL> SQL> SQL> SQL>   2    3    4
INDEX_NAME           TABLE_NAME COLUMN_NAM COLUMN_POSITION
-------------------- ---------- ---------- ---------------
PK_EMP               EMP        EMPNO                    1

SQL> select empno, ename from emp;

     EMPNO ENAME
---------- ----------
      7369 SMITH
      7499 ALLEN
      7521 WARD
      7566 JONES
      7654 MARTIN
      7698 BLAKE
      7782 CLARK
      7788 SCOTT
      7839 KING
      7844 TURNER
      7876 ADAMS
      7900 JAMES
      7902 FORD
      7934 MILLER
        15 NEO

15 rows selected.

SQL> update emp set empno = 16 where empno = 15;

1 row updated.

SQL> commit;

Commit complete.

SQL> select empno, ename from emp;

     EMPNO ENAME
---------- ----------
      7369 SMITH
      7499 ALLEN
      7521 WARD
      7566 JONES
      7654 MARTIN
      7698 BLAKE
      7782 CLARK
      7788 SCOTT
      7839 KING
      7844 TURNER
      7876 ADAMS
      7900 JAMES
      7902 FORD
      7934 MILLER
        16 NEO

15 rows selected.