Как объявить внешний ключ с условием ИЛИ, используя Oracle? - PullRequest
3 голосов
/ 02 декабря 2010

У меня есть таблица (A), первичный ключ которой является внешним ключом таблицы (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);

Возможно ли это?

Ответы [ 5 ]

4 голосов
/ 02 декабря 2010

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

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

4 голосов
/ 02 декабря 2010

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

Ваши варианты, как правило,

  • Создайте два разных столбца (bkey и ckey) в A, где bkey ссылается на B.bkey, а ckey ссылается на C.ckey и создает ограничение, гарантирующее, что в любой момент времени только один не является NULL.
  • Создайте некоторый вид «комбинированной сущности B & C», к которой B & C имеют внешние ключи, и сделайте внешний ключ в A ссылкой на ключ этой комбинированной сущности.

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

create table one_key( 
  col1 number, 
  col2 number, 
  check( nvl2(col1,1,0) + nvl2(col2,1,0) = 1 ) 
)
1 голос
/ 03 декабря 2010

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

В таблице PERSON может быть уникальный ключ PERSON_ID плюс атрибут PERSON_TYPE («CUST» или'SUPP').Если вы создаете первичный ключ для PERSON_ID, PERSON_TYPE, вы можете ссылаться на него в таблицах подтипов (SUPPLIER / CUSTOMER).

Затем вы добавляете уникальное ограничение на 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');

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

0 голосов
/ 03 декабря 2010

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

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
0 голосов
/ 02 декабря 2010

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...