2010-12-02 4 views
3

У меня есть таблица (A), первичным ключом которой является либо внешний ключ к таблице (B), либо таблица (C).Как объявить внешний ключ с условием ИЛИ с использованием Oracle?

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); 

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

+0

Oracle версии? – DCookie 2010-12-02 19:06:01

+0

@DCookie: 10gR2 – dacracot 2010-12-02 20:03:08

+0

@OMG Ponies: Ошибка при запуске в строке 1 в команде: альтер таблица А добавить ограничение BorCkey внешнего ключа (AKEY) ссылается на B (Bkey) или C (CKEY) отчет Ошибка: SQL Error: ORA- 01735: недопустимый параметр ALTER TABLE 01735. 00000 - «недопустимый параметр ALTER TABLE» – dacracot 2010-12-02 20:56:25

ответ

4

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

Ваши варианты обычно являются

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

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

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

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

+2

Ограничение не может ссылаться на представление, потому что вы не можете создать принудительное ограничение первичного ключа/уникального ограничения для представления. – 2010-12-02 19:15:02

+0

Кроме того, вы не можете создать уникальный индекс в представлении, что означает, что вы не можете создать внешний ключ для представления. Не уверен, что материализованное представление будет работать очень хорошо, если вообще. – DCookie 2010-12-02 19:22:27

4

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

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

1

Похоже, у вас есть некоторая форма отношений подтипа/супертип происходит. Типичным примером является «ПЕРСОН», который может быть либо «ЗАКАЗЧИКОМ», либо «ПОСТАВЩИКОМ».

Возможно, в таблице ПЕРСОНА есть уникальный ключ 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'); 

Его не очень, но типы/подтипы являются скорее концепцией объекта, чем реляционной.

0

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

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 
Смежные вопросы