Дизайн бази даних: два зв’язки від 1 до багатьох до однієї таблиці


20

Я повинен моделювати ситуацію, коли у мене є таблиця Chequing_Account (яка містить бюджет, номер iban та інші реквізити рахунку), яка повинна бути пов'язана з двома різними таблицями Person і Corporation, в яких обидва можуть мати 0, 1 або багато рахунків, що перевіряють.

Іншими словами, у мене є два стосунки від 1 до багатьох із однією таблицею Chequing account

Я хотів би почути рішення цієї проблеми, які відповідають нормам нормалізації. Більшість рішень, які я чув навколо себе, це:

1) знайти спільну сутність, до якої належать і Person, і корпорація, і створити таблицю зв’язків між цією таблицею Chequing_Account, в моєму випадку це неможливо, і навіть якби я хотів вирішити загальну проблему, а не цей конкретний екземпляр.

2) Створіть дві таблиці посилань PersonToChequingAccount та CorporationToChequingAccount, які пов’язують ці сутності з рахунками перевірки. Однак я не хочу, щоб дві особи мали однаковий обліковий запис, і я не хочу, щоб фізична особа та корпорація мали спільний доступ до рахунку! дивіться це зображення

http://i41.tinypic.com/35i6kbk.png

3) Створіть два закордонних ключі в шахівницькому рахунку, які вказують на корпорацію та фізичну особу, однак я б таким чином переконався, що особа та компанія можуть мати багато рахунків, що перевіряють, однак мені доведеться вручну переконатися, що для кожного рядка ChequingAccount не вказують обидва відносини Корпорація та Фізична особа, оскільки виписка рахунків є або корпорацією, або Фізичною особою. дивіться це зображення

http://i40.tinypic.com/1rpv9z.png

Чи є якесь більш чисте рішення цієї проблеми?


Чи замислювалися Чи Ви про те, наприклад , для OwnerTypeIDв ChecquingAccountтаблиці, з 1=Corporationі 2=NaturalPerson? Таким чином, вам потрібен лише один OwnerIDу ChecquingAccountтаблиці, який ви можете індексувати разом із OwnerTypeID.
RoKa

Мені потрібно не тільки знати, чи це корпорація чи фізична особа, але й знати відповідний ідентифікатор, тому мені потрібен ідентифікаційний номер, а не лише значення 1 або 2! Рішення 3 - це те, що я знайшов тут. У мене є дві колонки з ідентифікаторами для корпорації чи фізичної особи
dendini

2
Так, рішення - допустимий варіант. У більшості СУБД ви можете встановити, що лише один з двох FK є "активним" з обмеженням перевірки: CHECK (CorporationID IS NOT NULL AND NaturalPersonID IS NULL OR CorporationID IS NULL AND NaturalPersonID IS NOT NULL)хоча я набагато віддаю перевагу рішення 1 (але це лише я). Це набагато «чистіше».
ypercubeᵀᴹ

Так, я розумію, але ви можете мати в ChecquingAccountтаблиці запис OwnerTypeID=1і OwnerID=123, що вказує, що це тип Corporation, отже, ідентифікатор 123у Corporationтаблиці. OwnerTypeID повідомляє вам, яку таблицю, а OwnerID повідомляє вам ідентифікатор у цій таблиці.
RoKa

1
Як варіант №1 неможливий? Слово "Корпорація" в основному означає "бізнес, який є юридично особою", зрештою. Назвіть це Customersтаблицею.
Йон усіх торгів

Відповіді:


15

Реляційні бази даних не створені для ідеального вирішення цієї ситуації. Ви повинні вирішити, що для вас найважливіше, а потім зробити свої компроміси. У вас кілька цілей:

  • Підтримуйте третю нормальну форму
  • Підтримуйте референтну цілісність
  • Дотримуйтесь обмеження, що кожен рахунок належить або корпорації, або фізичній особі.
  • Збережіть можливість простого та безпосереднього отримання даних

Проблема полягає в тому, що деякі з цих цілей конкурують між собою.

Рішення для субтипірування
Ви можете вибрати рішення для підтипу, де ви створюєте супер-тип, який включає як корпорації, так і осіб. Цей супер-тип, ймовірно, має складений ключ природного ключа підтипу плюс атрибут розділення (наприклад customer_type). Це нормально, що стосується нормалізації, і це дозволяє забезпечити референтну цілісність, а також обмеження, що корпорації та особи взаємно виключають. Проблема полягає в тому, що це ускладнює пошук даних, тому що ви завжди повинні мати відділення залежно від того, customer_typeколи ви приєднаєтесь до облікового запису до власника облікового запису. Це, ймовірно, означає, UNIONщо у вашому запиті використовується багато повторюваних SQL.

Вирішення двох іноземних ключів
Ви можете обрати рішення, коли ви зберігаєте два зовнішніх ключі в таблиці рахунків, один - корпорації та один - особі. Це рішення також дозволяє підтримувати референтну цілісність, нормалізацію та взаємну ексклюзивність. Він також має той самий недолік пошуку даних, що і рішення для підтипу. Насправді це рішення так само, як і рішення про підгрупування, за винятком того, що ви стикаєтеся до проблеми розгалуження вашої логіки приєднання «швидше».

Тим не менш, багато модельєрів даних вважають, що це рішення поступається рішенню для підтипу через те, як застосовується взаємне обмеження виключності. У рішенні про субтипізацію ви використовуєте клавіші для забезпечення взаємної ексклюзивності. У двох рішеннях іноземного ключа ви використовуєте CHECKобмеження. Я знаю деяких людей, які мають необгрунтовану упередженість щодо обмежень перевірки. Ці люди вважають за краще рішення, яке зберігає обмеження в ключах.

Рішення атрибутів розділення атрибутів "денормалізованого"
Є ще один варіант, коли ви зберігаєте один стовпець із зовнішнім ключем у таблиці рахунків рахунків і використовуєте інший стовпець, щоб повідомити, як інтерпретувати стовпчик із іноземним ключем (RoKa'sOwnerTypeIDстовпчик). Це по суті виключає таблицю супер-типу в рішенні для підтипу, денормалізуючи атрибут розділення на дочірню таблицю. (Зауважте, що це не є строго "денормалізацією" згідно з формальним визначенням, оскільки атрибут розділення є частиною первинного ключа.) Це рішення здається досить простим, оскільки дозволяє уникнути наявності додаткової таблиці, щоб зробити більш-менш те ж саме, і це скорочує кількість стовпців іноземних ключів до одиниці. Проблема цього рішення полягає в тому, що воно не дозволяє уникнути розгалуження логіки пошуку і, крім того, не дозволяє підтримувати декларативну референтну цілісність. Бази даних SQL не мають можливості керувати одним стовпчиком із зовнішнім ключем для однієї з кількох батьківських таблиць.

Спільне рішення домену основного ключа
Один із способів, яким люди іноді займаються цим питанням, - це використовувати єдиний пул ідентифікаторів, щоб не було плутанини для будь-якого даного ідентифікатора, належить він до того чи іншого підтипу. Це, мабуть, спрацює досить природно за банківським сценарієм, оскільки ви не збираєтесь видавати один і той же номер банківського рахунку як корпорації, так і фізичній особі. Це має перевагу у тому, щоб уникнути необхідності в атрибуті розділення. Ви можете зробити це з таблицею супер-типу або без неї. Використання таблиці супер-типу дозволяє використовувати декларативні обмеження для забезпечення унікальності. В іншому випадку це повинно бути здійснено процедурно. Це рішення нормалізовано, але воно не дозволить вам підтримувати декларативну референтну цілісність, якщо ви не зберігаєте таблицю супер-типу. Це все ще не робить нічого, щоб уникнути складної логіки пошуку.

Отже, ви бачите, що не вдається мати чітку конструкцію, яка б відповідала всім правилам, і в той же час простоту пошуку даних. Ви повинні вирішити, де будуть ваші компроміси.


Моє рішення №2 до якої з ваших чотирьох груп належить? "Рішення атрибутів денормалізованого розділення" для мене не зовсім зрозуміло ..
dendini

@dendini - Рішення №2 вам не відповідає жодному із вирішених мною рішень. Це тому, що він не відповідає вимогам рахунку, що належить одній юридичній особі. Як ви визначили первинні ключі проміжних таблиць, вони перетинаються безліччю до багатьох. Якби первинні ключі були якраз corporation_id і person_idтоді у вас, по суті, було б рішення про підгрупування, за винятком того, що таблиця супер-типу була б розділена на дві частини, а зовнішній ключ був би інвертований, тому люди не могли мати кілька облікових записів. Цей вид перемагає мету.
Джоел Браун

Чудове пояснення. @JoelBrown, які наслідки для продуктивності рішення "Два зовнішні ключі" щодо запитів? Крім того, враховуючи, що замість 2 може бути 6 чи більше зовнішніх ключів: чи все-таки рекомендуєте ви такий підхід чи скоріше схиляєтесь до іншого?
Amadeo Gallardo

1
@AmadeoGallardo Відповідь "це залежить". Запит на ключ завжди досить ефективний, оскільки, як правило, ви можете розраховувати на індексне сканування принаймні, якщо не на пошук, і це швидкі операції. Проблема виникає, коли ви запитуєте обидві клавіші у рішенні двох іноземних ключів . Тут ви просите оптимізатор запитів зробити операцію або / або. У кращому випадку це вдвічі збільшить вартість запиту, як правило, трохи гірше, оскільки вам доведеться запитувати проти одного ключа, а потім іншого, а потім об'єднати результати.
Джоел Браун

@JoelBrown Денормалізовані майбутні версії SQL повинні дозволити такий підхід, дозволяючи визначити складний зовнішній ключ на основі двох стовпців RefIDі RefTableде RefTableє фіксований ідентифікатор, що ідентифікує цільову таблицю. Існує дуже багато випадків використання для цього типу ключа, і його багато для підтримання 10 або більше таблиць асоціацій / підтипів для забезпечення цілісності. Для тих випадків я створив це keyсам.
djmj
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.