Не знаєте, як перетворити змінну сутність у реляційну таблицю


9

ВСТУП І ВІДПОВІДАЛЬНА ІНФОРМАЦІЯ:

Наступний приклад ілюструє проблему, з якою я стикаюся:

Тварина має гонку, якою може бути кішка чи собака . Кішка може бути або сіамською, або перською . Собака може бути німецькою вівчаркою або лабрадором ретривером .

Тварина - це сильна сутність, тоді як його раса - це атрибут, який може мати одне з двох запропонованих значень (кішка чи собака). Обидва ці значення є складними (я тут додав лише тип собаки / кота, щоб проілюструвати проблему, але також може бути ім'я кота / собаки та купа інших речей).

ПРОБЛЕМА:

Я не знаю, як створити реляційні таблиці для цього прикладу.

МОЯ СИЛИ ДЛЯ РЕШЕННЯ ПРОБЛЕМИ:

Я спробував намалювати діаграму ER, використовуючи позначення Чена, яка представляє проблему, але будучи початківець, я не знаю, чи правильно це зробив. Ось що я отримав:

введіть тут опис зображення

Прошу вибачення, якщо я намалював щось не так, будь ласка, виправте мене, якщо це так. Я не бажаю просто отримати «безкоштовне рішення», а й навчитися вирішувати цю проблему, щоб в майбутньому вирішити її самостійно.

Єдине, що мені спадає на думку - це створити дві окремі таблиці, одну для котів та одну для собак. Також атрибут гонки в таблиці Animal зберігає лише значення кота чи собаки . Щось на зразок цього:

Animal< # Animal_ID, race, other attributes >
Cat < # Cat_ID, $ Animal_ID, breed >
Dog < # Dog_ID, $ Animal_ID, breed >

У мене справді погані почуття щодо мого рішення, і я боюся, що це неправильно, звідси і подальше питання.

ЗАПИТАННЯ:

  • Як я можу перетворити свій приклад на діаграму ER?
  • Як перетворити цю діаграму ER в реляційні таблиці?

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

Дякую.


1
Перетворення діаграм EER у таблиці можна знайти в цій роботі з 1986 року TJTeorey, D. Yang, JPFry: Методика логічного проектування реляційних баз даних за допомогою розширеної моделі взаємозв'язку особи . Це просто і один з моїх улюблених робіт.
чудо173

Відповіді:


11

Належна структура цього сценарію є підкласовою / спадковою моделлю і майже ідентична концепції, запропонованій у цій відповіді: Гетерогенний упорядкований список цінностей .

Модель, запропонована в цьому питанні, насправді досить близька тим, що Animalсутність містить тип (тобто race) та властивості, які є загальними для всіх типів. Однак необхідні дві незначні зміни:

  1. Видаліть поля Cat_ID та Dog_ID зі своїх відповідних об'єктів:

    Ключовим поняттям тут є те , що всі це Animal, незалежно від того race: Cat, Dog, Elephant, і так далі. Враховуючи, що початковою точкою, будь-який конкретний raceз Animalсправді не потребує окремого ідентифікатора, оскільки:

    1. Animal_IDунікальний
    2. то Cat, Dogі будь-які додаткові raceоб'єкти , додані в майбутньому не самі по собі, в повній мірі представляють собою будь - якої конкретної Animal; вони мають сенс тільки при використанні в поєднанні з інформацією , що міститься в батьківської сутності Animal.

    Отже, Animal_IDвластивість в Cat, Dogі т.д. суб'єктів є і PK, і FK назад до Animalсутності.

  2. Розрізняють типи breed:

    Тільки тому, що дві властивості мають одне й те саме ім'я, не означає, що ці властивості однакові, навіть якщо однакове ім'я передбачає таку залежність. У цьому випадку те, що ви насправді маєте, є насправді CatBreedі DogBreedяк окремі "типи"

Початкові примітки

  1. SQL характерний для Microsoft SQL Server (тобто T-SQL). Значить, будьте обережні щодо типів даних, оскільки вони не однакові у всіх RDBMS. Наприклад, я використовую, VARCHARале якщо вам потрібно зберігати що-небудь поза стандартним набором ASCII, ви дійсно повинні використовувати NVARCHAR.
  2. Поля ідентифікаторів таблиць "типу" ( Race, CatBreedі DogBreed) не збільшуються автоматично (тобто ІДЕНТИЧНІСТЬ у термінах T-SQL), оскільки вони є константами програми (тобто вони є частиною програми), які є статичними значеннями пошуку в базу даних і представлені як enums у C # (або інших мовах). Якщо значення додаються, вони додаються в контрольованих ситуаціях. Я зарезервую використання полів автоматичного збільшення для даних користувачів, які надходять через додаток.
  3. Конвенція про іменування, яку я використовую, - називати кожну таблицю підкласів, починаючи з імені основного класу, а потім імені підкласу. Це допомагає організувати таблиці, а також чітко вказує (не дивлячись на FK) відношення таблиці підкласу до основної таблиці сутності.
  4. Будь ласка, дивіться розділ "Остаточне редагування" наприкінці для примітки щодо переглядів.

"Порода" як "раса" -Специфічний підхід

Порода як діаграма, специфічна для раси
Цей перший набір таблиць - це таблиці пошуку / типи:

CREATE TABLE Race
(
  RaceID INT NOT NULL PRIMARY KEY
  RaceName VARCHAR(50) NOT NULL
);

CREATE TABLE CatBreed
(
  CatBreedID INT NOT NULL PRIMARY KEY,
  BreedName VARCHAR(50),
  CatBreedAttribute1 INT,
  CatBreedAttribute2 VARCHAR(10)
  -- other "CatBreed"-specific properties as needed
);

CREATE TABLE DogBreed
(
  DogBreedID INT NOT NULL PRIMARY KEY,
  BreedName VARCHAR(50),
  DogBreedAttribute1 TINYINT
  -- other "DogBreed"-specific properties as needed
);

Цей другий список є основним об'єктом "Тварини":

CREATE TABLE Animal
(
  AnimalID INT NOT NULL IDENTITY(1, 1) PRIMARY KEY,
  RaceID INT NOT NULL, -- FK to Race
  Name VARCHAR(50)
  -- other "Animal" properties that are shared across "Race" types
);

ALTER TABLE Animal
  ADD CONSTRAINT [FK_Animal_Race]
  FOREIGN KEY (RaceID)
  REFERENCES Race (RaceID);

Цей третій набір таблиць - це додаткові об'єкти підкласу, які заповнюють визначення кожного Raceз Animal:

CREATE TABLE AnimalCat
(
  AnimalID INT NOT NULL PRIMARY KEY, -- FK to Animal
  CatBreedID INT NOT NULL, -- FK to CatBreed
  HairColor VARCHAR(50) NOT NULL
  -- other "Cat"-specific properties as needed
);

ALTER TABLE AnimalCat
  ADD CONSTRAINT [FK_AnimalCat_CatBreed]
  FOREIGN KEY (CatBreedID)
  REFERENCES CatBreed (CatBreedID);

ALTER TABLE AnimalCat
  ADD CONSTRAINT [FK_AnimalCat_Animal]
  FOREIGN KEY (AnimalID)
  REFERENCES Animal (AnimalID);


CREATE TABLE AnimalDog
(
  AnimalID INT NOT NULL PRIMARY KEY, -- FK to Animal
  DogBreedID INT NOT NULL, -- FK to DogBreed
  HairColor VARCHAR(50) NOT NULL
  -- other "Dog"-specific properties as needed
);

ALTER TABLE AnimalDog
  ADD CONSTRAINT [FK_AnimalDog_DogBreed]
  FOREIGN KEY (DogBreedID)
  REFERENCES DogBreed (DogBreedID);

ALTER TABLE AnimalDog
  ADD CONSTRAINT [FK_AnimalDog_Animal]
  FOREIGN KEY (AnimalID)
  REFERENCES Animal (AnimalID);

Модель із використанням загального breedтипу відображається після розділу "Додаткові примітки".

додаткові нотатки

  1. Концепція, breedздається, є центром плутанини. Jcolebrand запропонував (у коментарі до питання), що breedє властивістю, спільною для різних races, а два інших відповіді включили її як таку у свої моделі. Це, однак, помилка, оскільки значення для breedне поділяються на різні значення race. Так, мені відомо, що дві інші запропоновані моделі намагаються вирішити це питання, роблячи raceбатьків breed. Хоча це технічно вирішує проблему взаємозв'язку, це не допомагає вирішити загальний моделюючий питання про те, що робити з невластивими властивостями, а також як обробити raceте, що не має breed. Але, якщо таке майно було гарантовано існувати для всіхAnimals, я також включу варіант для цього (нижче).
  2. Моделі, запропоновані vijayp та DavidN (які здаються ідентичними), не працюють, оскільки:
    1. Вони також
      1. не дозволяють зберігати загальні властивості (принаймні, не для окремих примірників будь-яких Animal), або
      2. вимагають, щоб усі властивості для всіх races зберігалися в Animalоб'єкті, що є дуже плоским (і майже нереляційним) способом подання цих даних. Так, люди роблять це постійно, але це означає мати багато полів NULL в рядку для властивостей, які не призначені для цього конкретного raceІ, знаючи, які поля в рядку пов'язані з конкретним raceзаписом.
    2. Вони не дозволяють додавання raceз Animalв майбутньому , яке не має breedу власності. І навіть якщо ALL Animals мають a breed, це не змінить структуру через те, що раніше було зазначено про breed: breedце залежить від race(тобто breedдля Catце не те саме, що breedдля Dog).

"Порода" як загальний / спільний підхід

введіть тут опис зображення
Будь ласка, запиши:

  1. Нижче SQL можна запустити в тій самій базі даних, що і модель, представлена ​​вище:

    1. RaceТаблиці одне і те ж
    2. Breedстіл новий
    3. До трьох Animalтаблиць додано а2
  2. Навіть Breedякщо це тепер загальна властивість, здається, це не правильно, що це не було Raceзазначено в основній / материнській структурі (навіть якщо це технічно відносно коректно). Отже, обидва RaceIDі BreedIDпредставлені в Росії Animal2. Для того, щоб запобігти невідповідності між RaceIDзазначеним в Animal2та a, BreedIDщо є для іншого RaceID, я додав FK в обох, RaceID, BreedIDщо посилаються на Унікальний обмеження цих полів у Breedтаблиці. Зазвичай я зневажаю вказуючи ФК на Унікальне обмеження, але ось одна з небагатьох поважних причин для цього. УНІКАЛЬНЕ ОБМЕЖЕННЯ логічно є "альтернативним ключем", що робить його дійсним для цього використання. Зверніть також увагу, що в Breedтаблиці все ще є ПК на просто BreedID.
    1. Причина того, що не потрібно використовувати просто ПК на комбінованих полях та відсутність Унікального обмеження, полягає в тому, що це дозволило BreedIDб повторити те саме через різні значення RaceID.
    2. Причина не перемикання, на яку оточують PK та Унікальний обмеження, полягає в тому, що це може бути не єдиним використанням BreedID, тому все одно слід посилатись на конкретне значення, Breedне маючи RaceIDдоступного.
  3. Хоча наступна модель працює, вона має два потенційні недоліки щодо спільної концепції Breed(і тому я віддаю перевагу Race-специфічним Breedтаблицям).
    1. Існує неявне припущення, що ВСІ значення Breedмають однакові властивості. У цій моделі немає простого способу мати розрізнені властивості між Dog"породами" та Elephant"породами". Однак все ж є спосіб зробити це, який відзначається в розділі "Остаточне редагування".
    2. Немає можливості поділитися Breedна більш ніж одну расу. Я не впевнений, чи бажано це робити (або, можливо, не в концепції тварин, але, можливо, в інших ситуаціях, які використовували б цей тип моделі), але це неможливо.
CREATE TABLE Race
(
  RaceID INT NOT NULL PRIMARY KEY,
  RaceName VARCHAR(50) NOT NULL
);

CREATE TABLE Breed
(
  BreedID INT NOT NULL PRIMARY KEY,
  RaceID INT NOT NULL, -- FK to Race
  BreedName VARCHAR(50)
);

ALTER TABLE Breed
  ADD CONSTRAINT [UQ_Breed]
  UNIQUE (RaceID, BreedID);

ALTER TABLE Breed
  ADD CONSTRAINT [FK_Breed_Race]
  FOREIGN KEY (RaceID)
  REFERENCES Race (RaceID);

CREATE TABLE Animal2
(
  AnimalID INT NOT NULL IDENTITY(1, 1) PRIMARY KEY,
  RaceID INT NOT NULL, -- FK to Race, FK to Breed
  BreedID INT NOT NULL, -- FK to Breed
  Name VARCHAR(50)
  -- other properties common to all "Animal" types
);

ALTER TABLE Animal2
  ADD CONSTRAINT [FK_Animal2_Race]
  FOREIGN KEY (RaceID)
  REFERENCES Race (RaceID);

-- This FK points to the UNIQUE CONSTRAINT on Breed, _not_ to the PK!
ALTER TABLE Animal2
  ADD CONSTRAINT [FK_Animal2_Breed]
  FOREIGN KEY (RaceID, BreedID)
  REFERENCES Breed (RaceID, BreedID);


CREATE TABLE AnimalCat2
(
  AnimalID INT NOT NULL PRIMARY KEY, -- FK to Animal
  HairColor VARCHAR(50) NOT NULL
);

ALTER TABLE AnimalCat2
  ADD CONSTRAINT [FK_AnimalCat2_Animal2]
  FOREIGN KEY (AnimalID)
  REFERENCES Animal2 (AnimalID);

CREATE TABLE AnimalDog2
(
  AnimalID INT NOT NULL PRIMARY KEY,
  HairColor VARCHAR(50) NOT NULL
);

ALTER TABLE AnimalDog2
  ADD CONSTRAINT [FK_AnimalDog2_Animal2]
  FOREIGN KEY (AnimalID)
  REFERENCES Animal2 (AnimalID);


Остаточне редагування (сподіваюсь ;-)

  1. Що стосується можливості (а потім складності) обробки різнорідних властивостей між типами Breed, то є можна використовувати один і той же підклас / поняття спадкування , але з Breedяк основним суб'єктом. У цьому налаштуванні Breedтаблиця матиме властивості, загальні для всіх типів Breed(як і Animalтаблиця), і RaceIDбуде представляти тип Breed(такий же, як у Animalтаблиці). Тоді ви б підклас таблиці , такі як BreedCat, BreedDogі так далі. Для менших проектів це може розглядатися як «надмірна інженерія», але воно згадується як варіант для ситуацій, які від цього виграють.
  2. Для обох підходів іноді допомагає створювати представлення даних як скорочення до повних сутностей. Наприклад, врахуйте:

    CREATE VIEW Cats AS
       SELECT  an.AnimalID,
               an.RaceID,
               an.Name,
               -- other "Animal" properties that are shared across "Race" types
               cat.CatBreedID,
               cat.HairColor
               -- other "Cat"-specific properties as needed
       FROM    Animal an
       INNER JOIN  AnimalCat cat
               ON  cat.AnimalID = an.AnimalID
       -- maybe add in JOIN(s) and field(s) for "Race" and/or "Breed"
  3. Хоча вони не входять до складу логічних сутностей, досить часто є поля аудиту в таблицях, щоб принаймні отримати уявлення про те, коли записи вставляються та оновлюються. Тож на практиці:
    1. CreatedDateПоле має бути додано до Animalтаблиці. Це поле не потрібне в жодній із таблиць підкласу (наприклад AnimalCat), оскільки рядки, що вставляються для обох таблиць, повинні виконуватися одночасно в рамках транзакції.
    2. LastModifiedDateПоле буде додано в Animalтаблицю і все таблиці підкласу. Це поле оновлюється лише в тому випадку, якщо оновлюється конкретна таблиця: якщо оновлення відбувається, AnimalCatале не використовується Animalдля певної AnimalID, тоді буде встановлено лише LastModifiedDateполе в AnimalCat.

2
Якимось чином отримую відчуття, що ти зрозумів, що саме моя проблема. Я дам вашій пов’язаній відповіді погляд і уважно її вивчу. Просто просте визначення таблиць також було б чудово (якщо запитів SQL занадто багато, щоб ви писали на даний момент). Якщо ви вирішили оновити свою публікацію за допомогою SQL запитів або визначень таблиць, залиште мені коментар. Ще раз дякую вам. З повагою.
AlwaysLearningNewStuff

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

@AlwaysLearningNewStuff Привіт. Отримав це повідомлення раніше, але не встиг дістатись до нього відразу. Я зміг знайти нове запитання, натиснувши на ваше ім’я вище, і воно показує всі ваші запитання :-).
Соломон Руцький

Я мав на увазі це питання . Коротше кажучи: у мене є 3 сутності з загальним атрибутом D, тому я хотів застосувати метод з вашої відповіді. Дві сутності мають спільний атрибут, Eякого немає в третьому об'єкті. Чи слід ігнорувати цей факт і застосовувати стандартне рішення, чи є спосіб додатково оптимізувати свій дизайн?
ЗавждиНавчанняNewStuff

4

По-перше, ви добре розрізняєте ER моделювання та реляційне моделювання. Багато новачків ні.

Ось кілька мовних слів, за допомогою яких можна шукати корисні статті в Інтернеті.

Ваш випадок - це класичний випадок класу / підкласу або, якщо вам подобається, типу / підтипу.

Фраза, яка використовується в моделюванні ER, - це "узагальнення / спеціалізація". І багато статей показують це в рамках моделювання EER (Enhanced Entity-Relationship). Це не було в оригінальній презентації Пітера Чена моделювання ER. Це було додано пізніше. Щоб отримати досить хороший підсумок gen / spec у форматі PDF, натисніть тут

Далі, перетворюючи регістр класу / підкласу в реляційне моделювання, ви розробляєте таблиці. Існує не один підхід. Два основні підходи називаються успадкуванням однієї таблиці та успадкуванням таблиці класів. У кожного є свої переваги та недоліки. Найкраща презентація цих двох конструкцій - від Мартіна Фаулера. Ви можете побачити його контури тут і тут .

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

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

Нарешті, у цій області є тег, який збирає такі питання, як ваше разом.
Ось:


1
+1 Що мене бентежить - це відсутність первинних ключів у діаграмах таблиці. Особливо в "classTableInheritance" я не бачу, що всі ці таблиці з'єднані одним і тим же первинним ключем.
чудо173

@ чудо173 дійсна точка. Чомусь Фоулер не включає ПК в діаграму. Є й інші статті, присвячені успадкуванню таблиці класів, які надають цю деталь. Не всі реалізації успадкування таблиці класів поєднують його з спільним первинним ключем. Рекомендую. Це трохи більше роботи за час вставки, але простіше і швидше в час приєднання.
Вальтер Мітті

3

Я бачу на можливій конструкції як

Таблиця Race

RaceId- PK- Int
RaceName - Varchar(50)

Таблиця Breed

BreedId - PK- Int
RaceId - FK - Int
BreedName - varchar(50)

Таблиця Animal

AnimalId - PK- Int
BreedId - FK - Int
Other Columns....

Ці ПК вверху будуть стовпчиком з автоматичним збільшенням. Інші стовпці Animalтаблиці можуть бути названі відповідно.

введіть тут опис зображення


Додатково я додав би поля з ключами раси та типу (це можуть бути тригери) у таблиці Animal, щоб полегшити пізніші індекси для підвищення швидкості.
Феліпе Алькасібар

0

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

Animal < # Animal_ID, Breed_ID, other attributes >
Breed < # Breed_ID, Race_ID >
Race < # Race_ID >

На мою думку, порода повинна мати лише одну расу. Отже, якщо ви зберігаєте породу в таблиці тварин, ви зможете визначити расу, приєднавшись до таблиці породи. Очевидно, додайте будь-які інші атрибути (ім’я, опис тощо) до таблиць породи та гонки за потребою.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.