Oracle уникальное ограничение и уникальный индекс - PullRequest
38 голосов
/ 23 сентября 2011

Может ли кто-нибудь уточнить, для чего нужен уникальный индекс без ограничения уникальности (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". Я полностью смущен этим поведением. Есть ограничение или нет?

Есть много статей, объясняющих, почему возможно иметь уникальное ограничение без уникального индекса; это ясно и имеет смысл. Однако я не понимаю причину уникального индекса без ограничений.

Ответы [ 3 ]

50 голосов
/ 23 сентября 2011

Ограничение и индекс - это отдельные логические объекты.Например, уникальное ограничение отображается в USER_CONSTRAINTS (или ALL_CONSTRAINTS или DBA_CONSTRAINTS).Индекс виден в USER_INDEXES (или ALL_INDEXES или DBA_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.

Но если мы говорим о прямом уникальном индексе, не основанном на функциях,вероятно, существует относительно немного случаев, когда на самом деле имеет смысл создавать индекс, а не создавать ограничение.С другой стороны, есть относительно немного случаев, когда это имеет большое значение на практике.Вы почти никогда не захотите объявлять ограничение внешнего ключа, которое ссылается на ограничение уникальности, а не ограничение первичного ключа, поэтому вы редко что-то теряете, только создав индекс и не создавая ограничение.

2 голосов
/ 08 октября 2015

Еще один момент, который может быть полезен в этом контексте: Отключение / удаление существующего уникального ограничения не удаляет базовый уникальный индекс. Вы должны отбросить уникальный индекс явно.

0 голосов
/ 28 октября 2018

Вы не можете сделать условную уникальность, объявив уникальное ограничение, но вы можете сделать это, объявив уникальный индекс.

Поддержите, если вы попытаетесь выполнить ниже:

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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...