2009-11-16 1 views
0

Я пытаюсь найти решение для этого.Вопросы, связанные с циклическими внешними ключами Oracle

Для класса базы данных, мне нужно реализовать следующее:

Table HUSBANDS: (Name Varchar2(10)) (Wife Varchar2(10)) 
Table WIVES: (Name Varchar2(10)) (Husband Varchar2(10)) 

и с использованием ограничений Oracle, enfore следующих правил:

  1. Нет два мужей не могут иметь такое же имя
  2. Нет двух жен могут иметь одно и то же имя
  3. Каждая жена должна иметь один и тот же муж
  4. Каждый муж должен иметь один и только один жена

До сих пор я реализовал таблицу в Oracle SQL:

create table husbands(
    name varchar2(10) not null 
    , wife varchar2(10) not null 
); 
create table wives(
    name varchar2(10) not null 
    , husband varchar2(10) not null 
); 

Я уверен, что я решил пункты 1 и 2 с использованием правильных первичных ключей:

alter table husbands 
    add constraint husbands_pk 
    primary key(name); 
alter table wives 
    add constraint wives_pk 
    primary key(name); 

И вот где я столкнулся с проблемами. Я полагал, что использование внешних ключей для выполнения шагов 3 и 4:

alter table husbands 
    add constraint husbands_fk_wife 
    foreign key(wife) 
    references wives(name); 
alter table wives 
    add constraint wives_fk_husband 
    foreign key(husband) 
    references husbands(name); 

Теперь тест мой профессор использует это, чтобы иметь возможность добавить семейную пару в базу данных. Проблема, с которой я столкнулась, заключается в том, как это сделать, используя только ограничения. Если бы я хотел добавить Джека и Джил в качестве супружеской пары, нельзя добавить мужа, пока не будет добавлена ​​жена. жена не может быть добавлена ​​до тех пор, пока не будет добавлен муж.
Я думаю, что моя проблема заключается в использовании внешних ключей. Ограничение проверки может работать в этой ситуации, но я не могу концептуализировать, как это будет работать.

ответ

0

1) setAutoCommit() как false 2) Вставляет запись в обе таблицы в одном модуле работы. 3) commit

+0

Отсутствующим существенной часть делает ограничение откладываемым. См. Http://www.oracle-base.com/articles/8i/ConstraintCheckingUpdates.php –

3

Альтернатива отложенным ограничениям является третьей таблицей (мужем, женой) с двумя уникальными ограничениями (один на муж, один на жену) и имеет ограничения ссылочной целостности между этим и мужским столом и женами Таблица. Столбцы жены/мужа на мужских/женских столах будут излишними и должны быть отброшены.

PS. Должны ли они быть ЖЕНЩИНАМИ, а не ЖЕНЬЯМИ?

+0

Я соглашаюсь на избыточность, но это было назначение. Я рад, что я не единственный, кто видит недостаток в этой проблеме. – sdellysse

+0

Хорошо - так каждый муж может иметь не более одной жены - но ваше решение позволяет мужьям без жен !!! Потому что вы не можете проверить это без отложенных ограничений! – Falco

2

Изучите отложенные ограничения (не новый тип, просто парам для существующих), до сих пор вы делали хорошо.

1

Отложенные ограничения - это правильный способ сделать это. Интересно, что существует альтернативный способ, однако - с установкой и Oracle 10gR2:

SQL> CREATE OR REPLACE TRIGGER husband_wife_trg AFTER INSERT ON husbands 
    2 FOR EACH ROW 
    3 BEGIN 
    4  INSERT INTO wives VALUES (:new.wife, :new.name); 
    5 END; 
    6/

Trigger created 

SQL> INSERT INTO husbands VALUES ('Husband A', 'Wife B'); 

1 row inserted 

SQL> SELECT * FROM wives; 

NAME  HUSBAND 
---------- ---------- 
Wife B  Husband A 

Я не люблю положить транзакционную логику в триггера, но если вы будете следовать этому пути, вам не нужны откладываемые ограничения.

+0

Я думал об этом, но он должен был быть без триггеров. – sdellysse

+0

Это будет работать в этом случае, потому что у вас нет дополнительной информации во второй таблице - если бы появились дополнительные поля, такие как (девичье имя, возраст, ...), триггер не смог справиться. Но все равно +1, потому что он фактически решает вопрос! – Falco

3

Необходимость использования отложенных ограничений часто является указателем на проблемы с дизайном. Разумеется, эта модель данных не очень хорошая: она не нормирована.Нормированное решение будет выглядеть следующим образом:

PERSON 
------ 
ID number 
NAME varchar2(30) 
PRIMARY KEY (ID) 


MARRIED_COUPLE 
-------------- 
PARTNER_1 number 
PARTNER_2 number 
PRIMARY KEY (PARTNER_1, PARTNER_2) 
FOREIGN KEY (PARTNER_1) REFERENCES (PERSON.ID) 
FOREIGN KEY (PARTNER_2) REFERENCES (PERSON.ID) 

Это имеет дополнительное преимущество в поддержке гражданского партнерства :) Если вы хотите, чтобы препятствовать двоеженству, то вы могли бы поставить уникальные ключи на PARTNER_1 или PARTNER_2.

Это сложнее моделировать культуры, в которых допускается полигиния или полиандрия.

редактировать

Что Давид возражая (в комментариях) заключается в следующем:

SQL> create table married_couple (partner_1 number, partner_2 number) 
    2/

Table created. 

SQL> alter table married_couple add primary key (partner_1, partner_2) 
    2/

Table altered. 

SQL> insert into married_couple values (1, 2) 
    2/

1 row created. 

SQL> insert into married_couple values (2,1) 
    2/

1 row created. 

SQL> 

Это действительный пункт, но она разрешима. Например, с Oracle я могу создать уникальную функцию, основанную на обеспечении уникальности перестановок.

SQL> delete from married_couple 
    2/

2 rows deleted. 

SQL> create unique index mc_uidx on married_couple 
    2  (greatest(partner_1, partner_2),least(partner_1, partner_2)) 
    3/

Index created. 

SQL> insert into married_couple values (1, 2) 
    2/

1 row created. 

SQL> insert into married_couple values (2,1) 
    2/
insert into married_couple values (2,1) 
* 
ERROR at line 1: 
ORA-00001: unique constraint (APC.MC_UIDX) violated 


SQL> 

Чтобы избежать многоженства, мы можем использовать подобный трюк. Мы не хотим этого:

SQL> insert into married_couple values (1,3) 
    2/

1 row created. 

Таким образом, нам необходимо два индекса:

SQL> delete from married_couple where partner_2 = 3; 

1 row deleted. 

SQL> create unique index mc1_uidx 
    2  on married_couple (greatest(partner_1, partner_2)) 
    3/

Index created. 

SQL> create unique index mc2_uidx 
    2  on married_couple (least(partner_1, partner_2)) 
    3/

Index created. 

SQL> insert into married_couple values (3, 1) 
    2/
insert into married_couple values (3, 1) 
* 
ERROR at line 1: 
ORA-00001: unique constraint (APC.MC2_UIDX) violated 


SQL> 

для тех, кто думает, что это обман, чтобы решить проблему моделирования данных с трюком реализации, я признаю себя «Виновен, как обвиняемый ", но у меня был долгий и трудный день.

+0

+1: Отличное предложение, циклические ограничения не могут быть правильно смоделированы, не приводя к проблемам. – Thorsten

+0

polyandry - всего лишь форма многоженства –

+0

@ammoQ - совершенно правильно, я должен был сказать «полигиния». – APC

0

Вам нужна третья таблица, не только для ее исправления, но и для правильной обработки многоженства/двоеженства, которое является законным в более чем 40 странах мира.

1

Глупая идея - почему бы просто не иметь единственную таблицу «Пары» с колонками «Husband_Name» и «Wife_Name», каждая из которых имеет уникальное ограничение? Кажется, мне это соответствует всем требованиям. :)

0

К сожалению - большинство ответов не адресация точной задачи под рукой:

«должен быть один и только один»

Это по существу означает: вы не можете вставить ни одного человека в базу данных !!! * Потому что у одного Человека не было бы точно одного партнера!

Так что только действительные решения:

  1. откладываемые Ограничения: Легко, как это может быть - просто отметьте свой Constraints отложенной, а затем вставить жену и мужа, и он будет проверять только целостность после фиксации (Я не знаю, что люди жалуются - это не обман или странно ... это обычная практика и единственным способом во многих коммерческих делах !!!)

  2. ВСТАВИТЬ ALL - по крайней мере, с новее Версии Oracle вы можете использовать инструкцию INSERT ALL, которая будет вставляться в сразу несколько таблиц. Таким образом, вы можете написать сингл «Insert wife and hsuband», который является приемлемым для многих случаев использования.

  3. Trigger: В этом специальном случае Trigger выполнит трюк - но как только у вас появятся дополнительные атрибуты, он больше не будет работать ...

Но все остальные ответы были просто неправильны для предложенной задачи: Два объектов с обязательным 1 к 1 соединение