Как объявить внешний ключ с использованием Oracle?

StackOverflow https://stackoverflow.com/questions/4338705

Вопрос

У меня есть таблица (а), первичный ключ которого является либо внешним ключом к таблице (b) или таблице (C).

create table A (
  akey number, 
  txt varchar2(10)
);

create table B (
  bkey number, 
  txt varchar2(10)
);

create table C (
  ckey number, 
  txt varchar2(10)
);

Что я хочу, это что-то вроде:

alter table A add constraint BorCkey foreign key (akey) references B(bkey)` or C(ckey);

Это возможно?

Это было полезно?

Решение

Нет, такого рода это невозможно в Oracle.

Ваши варианты обычно

  • Создайте две разные столбцы (BKEY и CKEY) в A, где BKEY REALTERATIONS B.BKEY и CKKEY RESTERTIONS C.ckey и создают ограничение, которое гарантирует, что только один ненул в любой момент времени.
  • Создайте какой-то «комбинированный B & C», который B & C имеет внешние ключей и сделать внешний ключ в ссылке ключ этого комбинированного объекта.

Если вы хотите ограничение, которое гарантирует, что ровно один из двух столбцов - это нулевой, и один не является нулевым для любой строки

create table one_key( 
  col1 number, 
  col2 number, 
  check( nvl2(col1,1,0) + nvl2(col2,1,0) = 1 ) 
)

Другие советы

Ограничение иностранного ключа является Один иностранный стол.
Это означает, что вам нужно использовать два оператора ALTER TABLE в этой ситуации для настройки внешних ключей для ссылки на две таблицы. Там нет возможности указать или в отношениях - значение в A.akey должен был бы существовать в обоих B.bkey а также C.ckey в то же время. Отказ Например, если B.bkey имеет значение null, но C.ckey не - тогда A.akey никогда не может иметь значение null. Зарубежные ключевые ключи отложительны в Oracle, но описанный поведение - это то, что вы столкнуетесь, если оба зарубежные ключи включены одновременно - вы не сможете включить ограничение, если все значения не удовлетворяют отношения.

Вам необходимо просмотреть ваши потребности в том, как упростить отношения, поэтому ему не нужно две таблицы, чтобы сделать эту работу.

Похоже, у вас есть некоторая форма отношения подтипа / супертип. Типичный пример - «человек», который может быть либо «клиентом», либо «поставщиком».

У вас может быть, в личном столе уникальный ключ Person_ID плюс атрибут Person_Type («Cust» или «SUPP»). Если вы создаете первичный ключ на Person_id, Person_Type, вы можете ссылаться на то, что в таблицах подтипа (поставщик / клиент).

Затем вы добавляете уникальное ограничение на Person_ID, чтобы убедиться, что любое значение person_id должно быть либо клиентом, либо поставщиком, но не обоим, и и проверяет ограничения на таблицах подтипа, чтобы только один тип представлен в таблице.

create table person
  (person_id     number,
   person_type   varchar2(4),
   name          varchar2(10),
    constraint person_pk primary key (person_id, person_type),
    constraint person_id_uk unique (person_id));

create table supplier
  (supplier_id   number,
   supplier_type varchar2(4),
   blah          varchar2(10),
  constraint supplier_pk primary key (supplier_id, supplier_type),
  constraint supp_pers_fk foreign key  (supplier_id, supplier_type)
    REFERENCES person (person_id, person_type)
  )
/
alter table supplier add constraint supp_type_ck check (supplier_type = 'SUPP');

Это не красиво, но типы / подтипы - это больше концепции объекта, чем реляционный.

Мое решение, вдохновленное Джастином:

CREATE OR REPLACE TRIGGER abc
  BEFORE INSERT OR UPDATE ON a
  FOR EACH ROW
  DECLARE
  v_testB NUMBER:= 0;
  v_testC NUMBER:= 0;
  BEGIN
    SELECT
      COUNT(bkey)
    INTO
      v_testB
    FROM
      b
    WHERE
      bkey = :new.aKey;
    SELECT
      COUNT(ckey)
    INTO
      v_testC
    FROM
      c
    WHERE
      ckey = :new.aKey;
    IF ((v_testB + v_testC) <> 1) THEN
      RAISE_APPLICATION_ERROR(-20002,'Foreign key to B or C missing.');
    END IF;
  END;
/
SHOW ERRORS TRIGGER abc

Создайте материализованное представление о том, что союзные таблицы B & C и указывают на ваше ограничение FK на вид

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top