Как объявить внешний ключ с использованием Oracle?
Вопрос
У меня есть таблица (а), первичный ключ которого является либо внешним ключом к таблице (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 на вид