Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Как лучше сделать ссылку на 2 сущности ? (Oracle и MS SQL)


Страницы:   1 2 3

ANB ©   (2005-12-20 12:01:00) 

Пример из налоговой (бухгалтерии) :
Есть 2 сущности : налогоплательщики юридические лица и физические лица. Естественно, набор полей - атрибутов у них отличается и логично хранить их в разных таблицах.
Из многих таблиц ссылка может быть как на ЮЛ, так и на ФЛ.
Видел несколько способов реализации подобного :
1. Отдельные таблицы ЮЛ и ФЛ. Завести в подчиненных таблицах по 2 ссылочных поля - отдельно на ЮЛ, отдельно на ФЛ. Повесить честные FK. Проблема - надо либо анализировать оба поля на null/0 либо добавлять поле - тип связки. Все это потом сильно усложнит запросы. Плюс придется вешать излишние составные индексы.
2. Отдельные таблицы ЮЛ и ФЛ. Организовать уникальность ID в этих таблицах (исключить пересечение). В ссылочное поле пишем просто ID. Проблемы - FK идут в лес, проверка целостности только хранимкой, запросы тоже не простые, в MS SQL в лес идут автоинкрементальные ID (В оракле просто общий секвенсер).
3. Дерево с ветками. Делаем 3 таблицы : Налогоплательщики (с общими полями для ЮЛ и ФЛ), отдельно ФЛ и ЮЛ, ссылающиеся на стержневую общую таблицу всех налогоплательщиков. Запросы писать легко. Работать будет намного шустрее первых 2-х способов. Минус - если удалять записи из таблицы, например, ФЛ, а в основной - не удалять, то получим висячие записи, т.к. FK это не отследит. Т.е. без проверки на хранимке тут не обойтись.

Какой способ лучше или есть свои мысли ?


Курдль   (2005-12-20 14:58:00) [21]


> - еще на триггерах бывает. Но там хоть на что то похоже.


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


ANB   (2005-12-20 14:56:00) [22]


> evvcom ©   (20.12.05 14:25) [18]
>
> > Но если защита стоит на хранимках, значит надо через хранимки
>
>
> Неверный в корне подход к решению задачи. Значит переписать
> защиту нафиг.

:))) На эту граблю я больше наступать не буду. Честные констрейнты - рулез форева.


> PS: Кто это мог придумать "защиту на хранимках"? Это еще
> что за звэрь?
- еще на триггерах бывает. Но там хоть на что то похоже. А это я работал с одним крутым ядром. Типа в оракле метаданные описываешь, а система сама генерит пакеты для защиты ссылочной целостности и в веб интерфейсе все это отображает. Идея неплохая была, но реализация - ой ой. Так я точно делать не буду.


Курдль   (2005-12-20 14:48:00) [23]


> Плюсы: экономия на джойнах, соответственно выигрыш во времени


Ты чего это за временем-то гоняешься? Миллиарды записей клиенту выдаешь?
Если в погоне за временем нарушать законы хранения данных - это только осложнит работу с базой. Данные должны храниться максимально денормализованно. А скорость выборки - это проблема СУБД и железа.
У меня сейчас много сущностей - трехступенчатые иерархии, а среднестатистический запрос обращается к 10 и более таблицам по разнообразным джоинам. И никаких проблем.
Правда для модификации и удаления данных служит специальный ДатаАдаптер,
который автоматически разруливает все каскадные закономерности (но такое возможно только при использовании многотабличных ДатаСэтов ADO.NET).

PS: Кто это мог придумать "защиту на хранимках"? Это еще что за звэрь?


evvcom   (2005-12-20 14:25:00) [24]


> Но если защита стоит на хранимках, значит надо через хранимки

Неверный в корне подход к решению задачи. Значит переписать защиту нафиг. Ну сейчас-то что-то новое разрабатываешь? Ну и сделай сразу правильно, зачем вестись на какие-то принятые кем-то неверные правила?


ANB   (2005-12-20 14:18:00) [25]


> evvcom ©   (20.12.05 14:14) [16]

Мне тоже так больше нравится. Но если защита стоит на хранимках, значит надо через хранимки :(((.
А тем, кто так базы чистил, строго настрого наказывали, чтобы данные меняли только через хранимки, т.к. констрейнтов вообще не было (это был случай 2).


evvcom   (2005-12-20 14:14:00) [26]


> Как только повесишь ссылочную целостность на хранимки

А ты вешай на триггера, тогда и умники по барабану. Мне, как разработчику, тоже гораздо удобнее работать sql-запросом с группой записей, чем через хранимку по одной. Я тоже выходит умник.


ANB   (2005-12-20 14:09:00) [27]


> поэтому опасения, что при удалении из подчиненной главная
> запись осиротеет, имхо, надуманны

Если бы. Как только повесишь ссылочную целостность на хранимки и не сделаешь возможность каскадного удаления, обязательно найдется человек, который будет чистить мусор обычными delete.
(с) Законы Мерфи
ЗЫ. Я уже видел много баз, чищенных таким образом.


> Sergey13 ©   (20.12.05 13:46) [12]

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


> А куда от него деваться?
- деваться некуда. Но если есть возможность сделать без дерева - лучше сделать без дерева.
Вот даже в оракле хотя и есть connect by, но попробуй сделать выборку, так чтобы в результате сортировка шла по группам, а сами группы и то, что внутри группы - по алфавиту.
Пример таблицы : Tree(ID, Parent_ID, Name)


evvcom   (2005-12-20 14:03:00) [28]

О, мой 5 вариант уже в
> Sergey13 ©   (20.12.05 13:46) [12]

:)


evvcom   (2005-12-20 14:02:00) [29]


> 1. Отдельные таблицы ЮЛ и ФЛ. Завести в подчиненных таблицах
> по 2 ссылочных поля - отдельно на ЮЛ, отдельно на ФЛ. Повесить
> честные FK. Проблема - надо либо анализировать оба поля
> на null/0

Повесить констрейнт на обязательное одно поле null, другое not null, а в запросах анализировать всего одно поле в case.
2 - мне совсем не нравится.

> 3. ... Работать будет намного шустрее первых 2-х способов.

Не уверен, что шустрее, ведь здесь джойнить надо уже 3 таблицы, а не 2.
У меня по 3 способу сейчас работает одна задача. Я подумываю иной раз для увеличения скорости все 3 собрать в одну. Это уже 5 вариант. Но у меня здесь своя кухня, свои проблемы, может и не выйдет.
Плюсы: экономия на джойнах, соответственно выигрыш во времени; отсутствие висячих записей.
Минусы: увеличение общего количества полей; каждый констрейнт not null специфичного для каждой сущности поля придется прописывать отдельно, а не привычной установкой/снятием галки; скан по индексу оптимизатор будет выбирать еще в меньшем количестве случаев, нежели в предыдущих вариантах.
По поводу "занимания места" null-полями: насколько я понял из курса лекций, Oracle физически не расходует место под поля записей, не содержащих значения. Так что тут все ок.


Sergey13   (2005-12-20 13:46:00) [30]

Если число типов сущностей невелико и постоянно, то можно сделать ссылки не на "столбовую" из "конкретных", а наоборот - несколько полей "столбовой" ссылаются каждое на свою "конкретную" . Заполнение конкретного поля говорит о типе сущности. Проблема удаления потомков вообще не стоит.

Почему то все решили, что надо обязательно 2 таблицы. Не вижу причин не рассматривать и возможность 1 таблицы со всеми возможными полями того и другого типа. Ничего криминального, ИМХО.


Desdechado   (2005-12-20 13:29:00) [31]

я предпочитаю (и постоянно использую) вариант 3
например, гдавная таблица разнообразных объектов с общими полями названия, примечания и типа
и куча других таблиц, в которых в зависимости от типа могут быть, а могут и не быть ссылки на главную
вся работа строится от главной, без нее ни одна выборка просто не идет
поэтому опасения, что при удалении из подчиненной главная запись осиротеет, имхо, надуманны
нельзя удалить "номер плательщика НДС" без удаления самого плательщика


Курдль   (2005-12-20 12:40:00) [32]


> ANB ©   (20.12.05 12:34) [9]
> Вообще то класическое парентовое дерево удобно при проектировании,
>  но довольно много проблем при реализации.


А куда от него деваться? Любая реализация "справочниковой идеологии" на нем зиждется. Это только апологеты MS SQL могут в холодном бреду посоветовать использовать GUID-ы для таких целей :)


ANB   (2005-12-20 12:34:00) [33]


> Курдль ©   (20.12.05 12:28) [7]

Не. Это мы когда такую технологию первый раз увидели, так ее назвали. Ессно, это не древовидная структура.
Просто есть ствол - все плательщики, и ветки - юрики и физики. Плюс к такой схеме потом легко доцеплять другие сущности. Похоже на дерево.
Вообще то класическое парентовое дерево удобно при проектировании, но довольно много проблем при реализации.


Johnmen   (2005-12-20 12:33:00) [34]

>ANB ©   (20.12.05 12:27) [6]

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


Курдль   (2005-12-20 12:28:00) [35]


> Это и есть вариант №3.


Наверное. Только меня смутило слово "Дерево с ветками..."
Это термин какого-то CASE инструментария?
Мне сразу представился вариант именно древовидной структуры, где все субъекты записаны в одной базе, но в иерархическом виде.
Типа


SBJ_ID = 1, "Налогоплательщики";
SBJ_ID = 2, "Прочие";
SBJ_ID = 3, SBJ_ID_PR = 1, "Физ. лица";
SBJ_ID = 4, SBJ_ID_PR = 1, "Юр. лица";
SBJ_ID = 5, SBJ_ID_PR = 3, "Петров А.В.";


ANB   (2005-12-20 12:27:00) [36]


> Johnmen ©   (20.12.05 12:22) [4]
> >ANB ©   (20.12.05 12:15) [2]
> >Это вариант №1 + 2. Со всеми минусами - в том числе - невозможно
> завести честные FK.
>
> Почему же невозможно? И какова в твоём понимании степень
> "честности"?

Честные - add constraint. Т.е. честно создать ограничение, а не проверять целостность в триггерах и хранимках.
Почему невозможно - а попробуй :)
Делать ссылку по условию "ИЛИ" на две таблицы синтаксис SQL не позволяет.
Если сделать 2 отдельных внешних ключа, то это будет уже условие "И", что тут совершенно не нужно. Если знаешь, как создать внешний ключ на 2 таблицы с условием "ИЛИ" - запости, плз.


ANB   (2005-12-20 12:23:00) [37]


> Курдль ©   (20.12.05 12:19) [3]

Это и есть вариант №3.


Johnmen   (2005-12-20 12:22:00) [38]

>ANB ©   (20.12.05 12:15) [2]
>Это вариант №1 + 2. Со всеми минусами - в том числе - невозможно завести честные FK.

Почему же невозможно? И какова в твоём понимании степень "честности"?


Курдль   (2005-12-20 12:19:00) [39]

Для таких типов данных существует совершенно однозначное решение в РБД.

Это наследование.

На концептуальном уровне это выглядит так:
Создается сущность "СУБЪЕКТЫ", от нее наследуются (inharitance) "ЮР_ЛИЦА" и "ФИЗ_ЛИЦА", причем с уникальным ID (mutually exclusive).

На физическом уровне получается 3 таблицы.
1. "СУБЪЕКТЫ" с идентификатором SBJ_ID и общим набором полей.
2. "ЮР_ЛИЦА" с внешним уникальным ключом по SBJ_ID и своим набором полей.
2. ФИЗ_ЛИЦА" с внешним уникальным ключом по SBJ_ID и своим набором полей.


ANB   (2005-12-20 12:15:00) [40]


> Johnmen ©   (20.12.05 12:07) [1]
> 4. Отдельные таблицы ЮЛ и ФЛ. Завести в подчиненных таблицах
> по 1 ссылочному полю - на ЮЛ/на ФЛ. И добавить поле признак
> ЮЛ/ФЛ.

Это вариант №1 + 2. Со всеми минусами - в том числе - невозможно завести честные FK.

ЗЫ. В вариант №3 забыл дописать - повесить честный FK.


Страницы:   1 2 3

Наверх

Титульная страница Поиск, карта сайта Написать письмо