Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > СУБД, общие вопросы > Связь с 2-мя таблицами через одну строку


Автор: Roo 28.12.2005, 13:05
Одна таблица должна быть связана по логике с двумя другими таблицами. Но, опять же по логике, только через одно поле. Т.е. в зависимости от конкретной строки (значение опред. поля либо =, либо != null) строка должна быть связана либо с одной таблицей, либо с другой. Как в такой ситуации по-грамотному спроектировать БД?

Автор: Akina 28.12.2005, 13:20
Цитата(Roo @ 28.12.2005, 14:05)
Как в такой ситуации по-грамотному спроектировать БД?

Разделить таблицу на две - в одной null, в другой не null. Другого способа сохранения логики не вижу.

Автор: Roo 28.12.2005, 13:28
Цитата
Разделить таблицу на две

В смысле, ввести 2 поля? Одно для одной табл., другое - для другой?

Автор: chief39 28.12.2005, 16:11
Знакомая ситуёвина smile
Ну что ж, поехали:

таблица MAIN содержит поле
ID NOT NULL
таблица sub1 содержит такое же поле
ID NOT NULL

таблица sub2 аналогична sub1
......

Внешние ключи subX.ID ссылаются на MAIN.ID

Теперь главное: надо сразу написать движок, который будет
поддерживать целостность в этих узелках.
То есть обеспечивать инсерты, делиты, апдэйты ключевых полей.
Небольшой но продуманный и быстренький. И всё, кроме селектов, ОБЯЗАНО будет
работать только через него. Лучше всего с помощью SP, которые пойдут как
обязательная часть БД.

В подтверждение скажу что по такому принципу спроектирована одна хорошо
известная мне система. на главную таблицу таким макаром ссылаются до десятка
таблиц. Причём таких узелков несколько в системе. Один раз написанный движок
органично дополнил встроенные механизмы контроля целостности СУБД. Всё это
чудовище работает уже почти 10 лет(!) у одной крупной международной компании
без нареканий. То есть ни одной траблы из-за того что часть функций на движке -
не было. smile

Посему рекомендую как опробованное техническое решение(Жаль что стандарт СКЛ таких механизмов не предполагает smile )

Автор: Roo 28.12.2005, 18:47
СПАСИБО за совет

Цитата
Жаль что стандарт СКЛ таких механизмов не предполагает

Это точно

Автор: Akina 29.12.2005, 10:13
Цитата(chief39 @ 28.12.2005, 17:11)
Жаль что стандарт СКЛ таких механизмов не предполагает

Такой механизм не отвечает требованиям нормализованности.

Автор: chief39 29.12.2005, 11:47
Цитата(Akina @ 29.12.2005, 10:13)
Такой механизм не отвечает требованиям нормализованности.

Абсолютно согласен. Но иногда приходится жертвовать красотой кода и идеальной структурой данных в угоду скорости, простоте и прочим богам. Жестокий иррациональный мир. В котором даже число ПИ - не очень круглое smile
P.S.
Roo, как успехи? Подводные камни попадаются или семь футов под килем?

Автор: YurikGL 2.1.2006, 20:29
Если не ошибаюсь, подобные штуки можно реализовать в СУБД, в которых поддерживается наследование таблиц.
Если это не представляется возможным, то проверку целостности можно организовать на триггерах, хотя, существуют случаи, когда триггерная целостность не работает. Тем не менее, ИМХО самым простым решением была бы организация проверки целостности триггерами, а выборки с помощью хранимых процедур.

Автор: chief39 3.1.2006, 11:50
Цитата(YurikGL @ 2.1.2006, 20:29)
Если не ошибаюсь, подобные штуки можно реализовать в СУБД, в которых поддерживается наследование таблиц.

Можно подробнее? ОО БД? Я думаю всем будет интересно.

Цитата(YurikGL @ 2.1.2006, 20:29)
Если это не представляется возможным, то проверку целостности можно организовать на триггерах,

Всё равно, при изменении данных, заранее известно какая из субтаблиц будет затронута и необходимы данные специфические для данной таблицы. Посему процедуры необходимы в любом случае. В них и будет контроль целостности. А если выбросить его в триггера - это лишнее распыление логики(и, возможно, замедление работы).

Цитата(YurikGL @ 2.1.2006, 20:29)
а выборки с помощью хранимых процедур.

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

P.S. О наследование таблиц можно ссылочку? Мне теперь и самому интересно smile

Автор: YurikGL 3.1.2006, 13:48
Цитата(chief39 @ 3.1.2006, 11:50)
Можно подробнее? ОО БД? Я думаю всем будет интересно.

Скажу сразу, что реально я с ОО БД не работал.
Почитать можно, например, здесь
http://zeus.sai.msu.ru:7000/database/articles/manifests/art_28_3_3.shtml

Самая известная объектная СУБД это - PostgreSQL

Так, запрос в яндексе "наследование таблиц PostgreSQL" вывел меня на http://amsand.narod.ru/articles/psql.html


Цитата(chief39 @ 3.1.2006, 11:50)
Всё равно, при изменении данных, заранее известно какая из субтаблиц будет затронута и необходимы данные специфические для данной таблицы. Посему процедуры необходимы в любом случае. В них и будет контроль целостности. А если выбросить его в триггера - это лишнее распыление логики(и, возможно, замедление работы).


Все же какая-то бизнес-логика должна быть? В конце концов, можно ввести поле, которое будет однозначно указывать, с какой таблицей должна быть обеспечена целостность.
А с триггерами проблема не столько в производительности, сколько факт, что они не всегда реально обеспечивают целостность. В одном из факов видел пример, как можно обмануть триггерную целостность.

Автор: LSD 3.1.2006, 13:52
Цитата(chief39 @ 3.1.2006, 11:50)
Всё равно, при изменении данных, заранее известно какая из субтаблиц будет затронута и необходимы данные специфические для данной таблицы. Посему процедуры необходимы в любом случае. В них и будет контроль целостности. А если выбросить его в триггера - это лишнее распыление логики(и, возможно, замедление работы).

Тут есть один недостаток: в этих процедурах требуется устанавливать некую общую блокировку (select for update, lock table или нечто более специфичное типа dbms_lock). И в большинсве случаев блокировка будет захватывать данных, больше чем надо.

Автор: Akina 4.1.2006, 01:11
Цитата(YurikGL @ 2.1.2006, 21:29)
проверку целостности можно организовать на триггерах

Как-то эта фраза меня аж в ступор ввела поначалу...

Если возникает при каких-либо мыслимых условиях необходимость организовывать ПРОВЕРКУ целостности - это нонсенс, это БД, в которой целостности нет от рождения. Т.е. единственный допустимый механизм нарушения целостности - это физическое разрушение части данных в файлах данных. Все остальное ОБЯЗАНО быть организовано так, чтобы разрушения целостности не было.

Отсюда - триггеры есть всего лишь средство (причем одно из) ПОДДЕРЖАНИЯ и ОБЕСПЕЧЕНИЯ целостности, причем суть выполняемых ими действий - это всего лишь выполнение каскадных изменений в соответствии с заложенной логикой целостности. Которое (средство то есть, в смысле триггеры) гроша ломаного не стОит, если не обернуто в транзакции.

Автор: YurikGL 4.1.2006, 08:44
Цитата

Как-то эта фраза меня аж в ступор ввела поначалу...

Разумеется, не проверки, а обеспечения smile

Имелось в виду, что внешние ключи нельзя заменять триггерами...

Автор: Vitkaz 12.11.2008, 22:57
А вообще может одна таблица связана с другими двумя одним полем ?

Автор: Zloxa 13.11.2008, 10:12
"ПО ЛОГИКЕ", так и давайте делать логикой. Логическая надстройка над физикой - вьюхи. А физику давайте реализовывать по законам физики. И не надо никаких извращений. Задача выеденного яйца не стоит.

Код

create table table1(id number primary key);
create table table2(id number primary key);
create table my_table(
   id number primary key
   ,Ref1 number references table1(id)
   ,Ref2 number references table2(id)
   ,Switcher char(1)
   ,constraint my_table$swch$chk check (Switcher is null and Ref1 is not null or Switcher is not null and ref2 is not null)
);
create or replace view my_view as 
  select id
          ,case when Switcher is null then Ref1
                   else Ref2
           end Ref
           ,Switcher
   from my_table;
create or replace trigger my_view$ii instead of insert on my_view
begin
  insert into my_table values(:new.id
                              ,case when :new.Switcher is null then :new.ref end
                              ,case when :new.Switcher is not null then :new.ref end
                              ,:new.Switcher);
end;
/
create or replace trigger my_view$iu instead of update on my_view
begin
  update my_table
    set ref1 = case when :new.Switcher is null then :new.ref end
        ,ref2 = case when :new.Switcher is not null then :new.ref end
        ,switcher = :new.Switcher
  where id = :new.id;
end;
/


ПС. Не посмотрел на дату старта топика :((( Как бы там ни было, пост оставляю.

Автор: Akina 13.11.2008, 11:11
Цитата(Zloxa @  13.11.2008,  11:12 Найти цитируемый пост)
ПС. Не посмотрел на дату старта топика 

Ну и что? "... лучше поздно, чем никому ..."  smile 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)