Моделиране на множество връзки много към много между едни и същи обекти в релационна база данни

Когато две таблици имат връзка много към много или когато една таблица има връзка много към много със себе си, можем да моделираме това с таблица за свързване.

Типът на връзката обаче може да надхвърли първоначалния тип, например:

Изисквания: имаме потребители. всеки потребител може да има 0 или повече други потребители като приятели

Решение: потребителска таблица и съединителна таблица, наречена "user_user".

След това откриваме ново изискване: някои приятелства са романтични или с други думи двама потребители могат да бъдат свързани по начин, различен от приятелството.

  • Решение a: добавете колона към съединителната таблица, която съдържа типа приятелство (приятел | партньор | бивш приятел) и т.н.

  • Решение b: преименувайте таблицата 'user_user' на 'friendships' (това би било по-добро име за начало с този подход) и създайте нова таблица, наречена romances, също свързвайки потребител с потребител.

След това откриваме още едно ново изискване: потребителите могат да дължат пари на други потребители. Отново можем да използваме същата съединителна маса или да създадем нова, наречена „дългове“. Този път интуицията ми е 100% да има отделна маса.

Всеки път, когато открием нов тип връзка или подтип на позната връзка, можем да добавим колона към една съединителна таблица или да създадем нова съединителна таблица.

Въпросът ми е какво е добро правило за решаване кога трябва да се създаде нова таблица?

Дали трябва да имаме повече от един ред на подредена двойка? Например, ако минали връзки никога не се изтриват, така че ако двама потребители са били приятели в миналото в продължение на две години, загубили са контакт и след това са се сприятелили отново, искаме да имаме и стария ред с начална и крайна дата, но с два реда дублира информацията в другата колона (старият ред показва, че потребителят дължи пари, новият не показва).

Дали, когато допълнителната колона не е логично определение на един тип връзка?

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

Не е добре: колоната за това колко пари един потребител притежава друг потребител може да бъде 1 към 1 за връзката, но логично не е описание на приятелството.

Ако знаем предварително, че две таблици ще имат много отношения много към много, това причина ли е да планираме много таблици за свързване или да направим една таблица за свързване, която е по-гъвкава (дори ако типът на връзката е не произволно)?


person user1852503    schedule 10.12.2016    source източник


Отговори (2)


От теб зависи. Можете да дефинирате „приятелство“ като различно от „романтична връзка“ и затова ви трябват две свързващи маси. Или можете да дефинирате „романтична обвързаност“ като специален случай на „приятелство“ и така се нуждаете от една маса. Бих се насочил към последното като по-просто и по-малко объркващо. (Ами ако едни и същи двама души са посочени като приятели, а също и като любовници?)

„Дължи пари на“ обаче е различно. Ако A е приятел с B, тогава B е приятел с A. Но ако A дължи пари на B, е невярно да се каже, че B дължи пари на A. Така че не само дефинирате различен вид връзка, но позиционирането на кое поле съдържа препратката към A и кое съдържа препратката към B става значимо. За това тогава би било най-добре да имате отделна съединителна маса.

person TommCatt    schedule 13.12.2016

Таблиците TL;DR представляват приложение/бизнес отношения/асоциации. Както в модела Entity-Relationship. Т.е. отношения. Както в релационния модел. Всеки път, когато се интересуваме от отделна връзка, разглеждаме нова таблица („свързване“/„асоциация“). Нормализация ни казва кога и как да разложим връзка/таблица на други или да комбинираме някои в една.


Ние идентифицираме връзка чрез някакъв предикат, т.е. шаблон на изявление, който ред превръща в предложение, т.е. изявление, което казва нещо, което ни интересува за нашето приложение. Редовете, които правят вярно изявление от предиката на таблицата, отиват в таблицата.

Employee(e, n, ...) -- employee identified by E is named N and ...
Manages(e, m) -- employee M manages employee E

Не можете да знаете какво казва една таблица за приложението или да я настроите според приложението, без да знаете неговия предикат! Когато заявявате "кардиналността" на "връзка", първо трябва да определите за каква връзка/асоциация/предикат говорите.

(За съжаление „връзката“ се използва от много така наречени ER методи и продукти за означаване на чужд ключ на таблица.)

Можем да комбинираме множество таблици в една или да заменим таблица с други, когато можем да реконструираме оригинала(ите) от новия. Тук можем да комбинираме таблиците по-горе в

-- employee identified by E is named N and ... AND employee M manages employee E
EmployeeM(e, n, ..., m)

Това се случва винаги да бъде JOIN на Employee & Manages, защото предикатът на JOIN е AND на предикатите на неговите аргументи. Но тъй като E е набор от общи колони и е уникален в една от тях, можем да реконструираме оригиналите чрез проекции на новото.

Това би било разумен дизайн, когато един служител може да има само точно един мениджър. Но ако един служител може да има един или повече мениджъри, тогава тази таблица, въпреки че все още ще съдържа редовете, които отговарят на този предикат и позволява реконструиране на оригиналите, ще показва аномалии при актуализиране, така че бихме предпочели оригиналите. И ако един служител може да има нула или един или нула или повече мениджъри, тогава пак можем да използваме тази таблица, но не само тази таблица, защото не може да ни каже за служители без мениджър(и). (Което прави оригиналният дизайн.) Ще ни трябва и таблица като Employee, но с различен предикат employee identified by E is named N and ... AND E has no manager. Или вместо тези две таблици можем да използваме само таблица < em>като EmployeeM, но това позволява нули чрез различен предикат employee identified by E is named N and ... AND ( employee M manages employee E OR M IS NULL AND E has no manager ).

Прочетете за оригиналния модел/метод на Chen ER, където има типове обекти, икони и таблици и типове отношения, икони и таблици. Всеки тип връзка е ясно диаграмиран като диамант. Всеки ред ясно представя участието на тип обект (възможно асоциативен тип обект) в тип връзка, т.е. ясно представя FK между таблиците. Докато много от така наречените ER методи дори не правят разграничение между обекти и взаимоотношения. (Не е необходимо това да е добро или лошо, но техните презентации обикновено не обясняват как да се моделира правилно.)

Релационният модел не се интересува от обекти и връзки сами по себе си. Неговите таблици са просто релации на стойности. ER и така наречените ER методи правят ненужно и ограничаващо произволно разграничение между обекти и връзки. Естествено, таблицата все още може да каже какво прави за приложението, както в ER модел, тъй като подредовете от стойности могат да идентифицират обекти. Вижте този отговор.

Нормализирането ви казва кога и как да разложите предиката/таблицата на връзката на по-малки (които са нейни проекции, които AND/JOIN обратно към нея), и ви казва кога и как да комбинирате множество релации ' предикати/таблици в едно (чрез AND/JOIN, използвайки проекция за реконструиране).

PS Няма нищо лошо в дублираните стойности сами по себе си. Това, което може да бъде проблем, е когато множество редове предполагат едно и също нещо за приложението, като са в или не в таблици според вашия избор на предикати. Не всички подобни излишъци са погрешни; просто неконтролираното излишък е погрешно. Като цяло искаме да имаме дизайни, които са възможно най-много в 5NF. (Т.е. намаляване на аномалиите при актуализиране, сложността на предикатите и ограниченията.)

person philipxy    schedule 11.12.2016