Oracle唯一约束和唯一索引

时间:2011-09-22 21:37:59

标签: oracle unique-key

有人可以澄清在没有唯一约束的情况下拥有唯一索引(Oracle)的目的是什么? 例如,

create table test22(id int, id1 int, tmp varchar(20));
create unique index idx_test22 on test22(id);
insert into test22(id, id1, tmp) values (1, 2, 'aaa'); // ok
insert into test22(id, id1, tmp) values (1, 2, 'aaa'); // fails, ORA-00001: unique   
  // constraint (TEST.IDX_TEST22) violated

到目前为止看起来有一个约束。但是

create table test33(id int not null primary key, 
test22_id int not null, 
foreign key(test22_id) references test22(id) );

也因"ORA-02270: no matching unique or primary key for this column-list"而失败。 我完全被这种行为搞糊涂了。是否存在约束?

有很多文章解释了为什么没有唯一索引就可以拥有唯一约束;这很清楚,也很有道理。但是,我不理解没有约束的唯一索引的原因。

4 个答案:

答案 0 :(得分:49)

约束和索引是单独的逻辑实体。例如,USER_CONSTRAINTS(或ALL_CONSTRAINTSDBA_CONSTRAINTS)中会显示唯一约束。索引在USER_INDEXES(或ALL_INDEXESDBA_INDEXES)中可见。

索引强制执行唯一约束,尽管有可能(有时是必要的)使用非唯一索引强制执行唯一约束。例如,使用非唯一索引强制执行可延迟的唯一约束。如果在列上创建非唯一索引并随后创建唯一约束,则还可以使用该非唯一索引来强制执行唯一约束。

实际上,唯一索引的作用非常类似于唯一的,不可延迟的约束,因为它引发了唯一约束引发的相同错误,因为唯一约束的实现使用索引。但它并不完全相同,因为没有约束。因此,正如您所见,没有唯一约束,因此您无法创建引用该列的外键约束。

在某些情况下,您可以创建一个无法创建唯一约束的唯一索引。例如,基于函数的索引强制执行条件唯一性。如果我想创建一个支持逻辑删除的表,但确保COL1对于所有未删除的行是唯一的

SQL> ed
Wrote file afiedt.buf

  1  CREATE TABLE t (
  2    col1 number,
  3    deleted_flag varchar2(1) check( deleted_flag in ('Y','N') )
  4* )
SQL> /

Table created.

SQL> create unique index idx_non_deleted
  2      on t( case when deleted_flag = 'N' then col1 else null end);

Index created.

SQL> insert into t values( 1, 'N' );

1 row created.

SQL> insert into t values( 1, 'N' );
insert into t values( 1, 'N' )
*
ERROR at line 1:
ORA-00001: unique constraint (SCOTT.IDX_NON_DELETED) violated


SQL> insert into t values( 1, 'Y' );

1 row created.

SQL> insert into t values( 1, 'Y' );

1 row created.

但是如果我们谈论的是一个直接的,基于非函数的直接索引,那么创建索引而不是创建约束的情况可能相对较少。另一方面,在实践中有很大差异的情况相对较少。您几乎从不想要声明引用唯一约束而不是主键约束的外键约束,因此您很少通过仅创建索引而不创建约束来丢失某些内容。

答案 1 :(得分:2)

在这种情况下可能有用的另一点是: 禁用/删除现有唯一约束不会删除基础唯一索引。您必须明确删除唯一索引。

答案 2 :(得分:1)

正如其他答案中已经解释的那样:约束和索引是不同的实体。但是他们缺乏对该主题的精确定义和官方评论。在讨论这两个实体之间的关系之前,让我们先看看它们彼此独立的目的。

约束的目的 1

使用约束来定义完整性约束-一种限制数据库中值的规则。

索引的目的 2

您可以在列上创建索引以加快查询速度。 索引可更快地访问数据,用于返回表行的一小部分的操作。

通常,在以下任何一种情况下,您都应该在列上创建索引:

  • 经常查询该列。
  • 该列上存在参照完整性约束。
  • 该列上存在UNIQUE键完整性约束。

现在我们知道约束和索引是什么,但是它们之间的关系是什么

索引与约束之间的关系为 3

  • 约束可能会创建索引或使用现有索引来有效实施自身。例如,PRIMARY KEY约束将创建索引(依赖于唯一索引或非唯一索引),或者将找到现有的合适索引并使用它。

  • 索引与约束无关。索引就是索引。

因此,约束可能会创建/使用并建立索引。索引就是索引,仅此而已。

因此,总结一下,直接解决您问题中的以下句子:

但是,我不理解没有约束的唯一索引的原因。

索引可加快查询和完整性检查(约束)的速度。此外,对于条件唯一性,使用唯一(功能)索引,因为这不能通过约束来实现。

希望这会为整个主题带来更多的说明,但是原始问题的一个方面仍然没有答案:

为什么不存在约束时会出现以下错误:

ORA-00001:违反了唯一约束(TEST.IDX_TEST22)

答案很简单:没有没有约束,并且错误消息名字错误

有关相同问题,请参见正式的“ Oracle Ask TOM”评论 4

这不是约束。错误消息“ misnames”。
如果这是一个约束,则可以为其创建外键-但不能。

希望有帮助。

链接:

1 Oracle 10g Documentation on Constraints

2 Oracle 10g Documentation on Selecting an Index Strategy

3 4 "Oracle Ask TOM" answer to a similar problem

答案 3 :(得分:0)

不能通过声明唯一约束来使条件唯一,但是可以通过声明唯一索引来做到。

如果尝试在下面执行,则提供支持:

alter table test22 
add constraint test22_u 
unique (id, case when tmp = 'aaa' then null else tmp end);

ORA-00904: : invalid identifier 

但是如果可以通过使用唯一索引来实现

create unique index test22_u 
on test22 ( customer_id, 
case when is_default = 'Y' then null else address_id end)