这两天在开发过程中,有个需求,就是找出某个schema的所有主键索引和唯一约束索引的名称,逻辑中用到了dba_indexes,其中存在一个字段叫UNIQUENESS,官方文档解释是说该字段会标记索引是唯一的(UNIQUE)还是非唯一的(NONUNIQUE),能不能这样理解,对主键索引和唯一约束索引来说,这个字段应该是UNIQUE?

主键和唯一约束的索引肯定唯一?_sql

如果按常规创建主键约束,自动创建的索引确实这个字段是UNIQUE,

SQL> create table t(id number);
Table created.


SQL> alter table t add constraint pk_t primary key(id);
Table altered.


SQL> select table_name, index_name, uniqueness from dba_indexes
  2  where table_name='T' and owner='BISAL';
TABLE_NAME                INDEX_NAME                UNIQUENESS
------------------------- ------------------------- ---------------
T                         PK_T                      UNIQUE

如果按常规创建唯一约束,自动创建的索引确实这个字段是UNIQUE,

SQL> create table t(id number);
Table created.


SQL> alter table t add constraint uk_t unique(id);
Table altered.


SQL> select table_name, index_name, uniqueness from dba_indexes
  2  where table_name='T' and owner='BISAL';
TABLE_NAME                INDEX_NAME                UNIQUENESS
------------------------- ------------------------- ---------------
T                         UK_T                      UNIQUE

但如果我们先创建非唯一索引,然后增加主键,主键就会使用这个索引作为主键索引,但是此时索引的UNIQUENESS字段值就是NONUNIQUE,

SQL> create table t(id number);
Table created.


SQL> create index idx_t on t(id);
Index created.


SQL> alter table t add constraint pk_t primary key(id);
Table altered.


SQL> select table_name, index_name, uniqueness from dba_indexes
  2  where table_name='T' and owner='BISAL';
TABLE_NAME                INDEX_NAME                UNIQUENESS
------------------------- ------------------------- ---------------
T                         IDX_T                     NONUNIQUE

但这不会影响主键的功能,

SQL> insert into t values(1);
1 row created.


SQL> insert into t values(1);
insert into t values(1)
*
ERROR at line 1:
ORA-00001: unique constraint (BISAL.PK_T) violated

同样地,对唯一约束,如果选择先创建非唯一索引,再增加唯一约束的操作,索引字段的UNIQUENESS就是NONUNIQUE,

SQL> create table t(id number);
Table created.


SQL> alter table t add constraint uk_t unique (id);
Table altered.


SQL> select table_name, index_name, uniqueness from dba_indexes
  2  where table_name='T' and owner='BISAL';
TABLE_NAME                INDEX_NAME                UNIQUENESS
------------------------- ------------------------- ---------------
T                         IDX_T                     NONUNIQUE

同样不会影响唯一约束的作用,

SQL> insert into t valueS(1);
1 row created.


SQL> insert into t values(1);
insert into t values(1)
*
ERROR at line 1:
ORA-00001: unique constraint (BISAL.UK_T) violated


SQL> insert into t values('');
1 row created.

因此,dba_indexes的UNIQUENESS字段值是表示索引的唯一性,和约束没有直接的关联。主键约束和唯一约束所对应的索引UNIQUENESS不一定就是UNIQUE,只有当这两种约束都自动创建索引/手工先创建唯一索引的时候,UNIQUENESS的值才是UNIQUE,但是即使是NONUNIQUE,不会影响主键约束和唯一约束的作用。

碰巧前几天,墨天轮每日一题,出了这道题,和上述操作存在异曲同工之处,

主键和唯一约束的索引肯定唯一?_sqlserver_02

但是这道题不是很严谨,创建成功有前提,就是当前表中不存在重复的数据,如果存在重复的数据,创建会提示错误,如下所示,

SQL> insert into test values(1);
1 row created.


SQL> insert into test values(1); 
1 row created.


SQL> create index idx_test_01 on test(id);
Index created.


SQL> alter table test add constraint pk_test primary key(id);
alter table test add constraint pk_test primary key(id)
                                *
ERROR at line 1:
ORA-02437: cannot validate (BISAL.PK_TEST) - primary key violated

再扩展下,如果当前表存在重复数据,再创建唯一索引,此时会提示错误,

SQL> create unique index idx_test_01 on test(id);
create unique index idx_test_01 on test(id)
                                   *
ERROR at line 1:
ORA-01452: cannot CREATE UNIQUE INDEX; duplicate keys found

如果创建了唯一索引,再插入重复的值,会提示唯一约束冲突的错误,但此时其实没有任何约束,

SQL> create unique index idx_test_01 on test(id);
Index created.


SQL> insert into test values(1);
1 row created.


SQL> insert into test values(1);
insert into test values(1)
*
ERROR at line 1:
ORA-00001: unique constraint (BISAL.IDX_TEST_01) violated


SQL> select constraint_name, index_name from 
     user_constraints where table_name='TEST';
no rows selected

说明如果仅存在唯一索引的时候,他会保证数据的唯一性。如果存在主键或者唯一约束,即使索引不唯一,还是能限制数据的重复性。