ВВЕДЕНИЕ И СООТВЕТСТВУЮЩАЯ ИНФОРМАЦИЯ:
Следующий пример иллюстрирует проблему, с которой я сталкиваюсь:
Животное имеет расу, которая может быть кошкой или собакой . Кошка может быть или сиамской или персидской . Собака может быть немецкой овчаркой или лабрадором-ретривером .
Животное - сильная сущность, в то время как его раса - это атрибут, который может иметь одно из двух предложенных значений (кошка или собака). Оба эти значения являются сложными (я добавил здесь только тип собаки / кошки, чтобы проиллюстрировать проблему, но также может быть имя кошки / собаки и куча других вещей).
ПРОБЛЕМА:
Я не знаю, как создать реляционные таблицы для этого примера.
МОИ УСИЛИЯ ДЛЯ РЕШЕНИЯ ПРОБЛЕМЫ:
Я попытался нарисовать диаграмму ER, используя обозначение Чена, которая представляет проблему, но, будучи новичком, я не знаю, правильно ли я это сделал. Вот что я получил:
Я прошу прощения, если я нарисовал что-то не так, пожалуйста, поправьте меня, если это так. Я не хочу просто получить «бесплатное решение», но также научиться решать эту проблему, чтобы я мог решить ее самостоятельно в будущем.
Единственное, что мне приходит в голову, - это создать две отдельные таблицы: одну для кошек и одну для собак. Кроме того, атрибут гонки в таблице Animal будет хранить только значение кошки или собаки . Что-то вроде этого:
Animal< # Animal_ID, race, other attributes >
Cat < # Cat_ID, $ Animal_ID, breed >
Dog < # Dog_ID, $ Animal_ID, breed >
У меня действительно плохое предчувствие по поводу моего решения, и я боюсь, что оно неверное, поэтому вопрос ниже.
ВОПРОСОВ:
- Как я могу преобразовать мой пример в диаграмму ER?
- Как преобразовать эту диаграмму ER в реляционные таблицы?
Если требуется дополнительная информация, оставьте комментарий, и я обновлю свой пост как можно скорее. Также не стесняйтесь добавлять соответствующие теги, так как я довольно новичок здесь.
Спасибо.
источник
Ответы:
Подходящей структурой для этого сценария является модель подкласса / наследования, и она почти идентична концепции, предложенной мною в этом ответе: гетерогенный упорядоченный список значений .
Модель, предложенная в этом вопросе, на самом деле довольно близка в том, что
Animal
сущность содержит тип (то естьrace
) и свойства, которые являются общими для всех типов. Однако есть два небольших изменения, которые необходимы:Удалите поля Cat_ID и Dog_ID из их соответствующих объектов:
Ключевым понятием здесь является то , что все это
Animal
, независимо от тогоrace
:Cat
,Dog
,Elephant
, и так далее. Учитывая , что отправной точкой, какого - либо конкретногоrace
изAnimal
не действительно нужен отдельный идентификатор с:Animal_ID
уникаленCat
,Dog
и любые дополнительныеrace
объекты , добавленные в будущем не сами по себе, в полной мере представляют собой какой - либо конкретнойAnimal
; они имеют значение только при использовании в сочетании с информацией, содержащейся в родительской сущностиAnimal
.Следовательно,
Animal_ID
свойство вCat
,Dog
и т.д. сущности является как PK и FK обратно кAnimal
лицу.Различают типы
breed
:То, что два свойства имеют одно и то же имя, не обязательно означает, что эти свойства одинаковы, даже если одно и то же имя подразумевает такие отношения. В этом случае то, что у вас есть на самом деле, на самом деле
CatBreed
иDogBreed
как отдельные «типы»Начальные заметки
VARCHAR
но если вам нужно хранить что-либо за пределами стандартного набора ASCII, вы должны действительно использоватьNVARCHAR
.Race
,CatBreed
иDogBreed
) являются не автоматическим приращением (т.е. Идентичности в терминах T-SQL) , потому что они являются константами приложения (т.е. они являются частью приложения) , которые являются статическими значениями столбца просмотра в элементе базы данных и представлены какenum
s в C # (или других языках). Если значения добавляются, они добавляются в контролируемых ситуациях. Я резервирую использование полей автоинкремента для пользовательских данных, которые поступают через приложение.«Порода» как «раса» - специфический подход
Этот первый набор таблиц - это таблицы поиска / типов:
Этот второй листинг является основным объектом «Animal»:
Этот третий набор таблиц является дополнительными объектами подкласса, которые завершают определение каждого
Race
изAnimal
:Модель, использующая общий
breed
тип, показана после раздела «Дополнительные примечания».Дополнительные замечания
breed
кажется, является центром путаницы. Jcolebrand (в комментарии к вопросу) предположил, чтоbreed
это свойство является общим для разныхrace
s, и два других ответа интегрированы как таковые в их модели. Это ошибка, однако, потому что значения дляbreed
не разделяются между различными значениямиrace
. Да, я знаю, что две другие предложенные модели пытаются решить эту проблему, сделавrace
одного из родителейbreed
. Хотя это технически решает проблему взаимоотношений, это не помогает решить общий вопрос моделирования о том, что делать с необычными свойствами, и как обрабатывать объектrace
, у которого нетbreed
. Но, в случае, если такая собственность гарантированно существует во всехAnimal
s, я включу опцию для этого (ниже).Animal
), илиrace
s были сохранены вAnimal
объекте, который является очень плоским (и почти нереляционным) способом представления этих данных. Да, люди делают это постоянно, но это означает наличие множества пустых полей в строке для свойств, которые не предназначены для этого конкретногоrace
И, зная, какие поля в строке связаны с конкретнымrace
объектом этой записи.race
изAnimal
в будущем , которое не имеетbreed
в собственности. И даже если у ВСЕХAnimal
естьbreed
, это не изменит структуру из-за того, о чем ранее было отмеченоbreed
: этоbreed
зависит отrace
(то естьbreed
forCat
- это не то же самое, что иbreed
дляDog
).«Порода» как подход к общей / совместной собственности
Пожалуйста, обратите внимание:
SQL ниже может быть запущен в той же базе данных, что и модель, представленная выше:
Race
Таблицы одно и то жеBreed
Стол новыйAnimal
таблицы были добавлены с2
Breed
будучи общепринятым в настоящее время свойством, кажется неправильным неRace
указывать в основной / родительской сущности (даже если это технически корректно с точки зрения отношений). Итак, обаRaceID
иBreedID
представлены вAnimal2
. Чтобы предотвратить несоответствие междуRaceID
отмеченными вAnimal2
и aBreedID
для другогоRaceID
, я добавил FK для обоих,RaceID, BreedID
который ссылается на УНИКАЛЬНОЕ ОГРАНИЧЕНИЕ этих полей вBreed
таблице. Я обычно презираю указание ФК на УНИКАЛЬНОЕ ОГРАНИЧЕНИЕ, но вот одна из немногих веских причин для этого. УНИКАЛЬНОЕ ОГРАНИЧЕНИЕ логически является «альтернативным ключом», что делает его действительным для этого использования. Также обратите внимание, что наBreed
столе по-прежнему есть ПКBreedID
.BreedID
повторять одно и то же для разных значенийRaceID
.BreedID
, поэтому все еще должна быть возможность ссылаться на конкретное значение,Breed
не имеяRaceID
доступного.Breed
(и именно поэтому я предпочитаю таблицы,Race
специфичные для конкретного пользователяBreed
).Breed
имеют одинаковые свойства. В этой модели нет простого способа иметь разнородные свойства междуDog
«породами» иElephant
«породами». Тем не менее, есть еще способ сделать это, что указано в разделе «Окончательное редактирование».Breed
более чем одну расу. Я не уверен, что это желательно делать (или, возможно, не в концепции животных, но, возможно, в других ситуациях, которые будут использовать этот тип модели), но здесь это невозможно.Окончательное редактирование (надеюсь ;-)
Breed
, то есть можно использовать один и то же подкласс / понятие наследования , но сBreed
как основным субъектом. В этой настройкеBreed
таблица будет иметь свойства, общие для всех типовBreed
(как иAnimal
таблица), иRaceID
будет представлять типBreed
(такой же, как вAnimal
таблице). Тогда вы бы подкласс таблицы , такие какBreedCat
,BreedDog
и так далее. Для небольших проектов это может считаться «чрезмерным проектированием», но это упоминается как вариант для ситуаций, которые выиграют от этого.Для обоих подходов иногда помогает создавать представления как ярлыки для полных сущностей. Например, рассмотрим:
CreatedDate
Поле должно быть добавлено кAnimal
таблице. Это поле не требуется ни в одной из таблиц подкласса (напримерAnimalCat
), поскольку строки, вставляемые для обеих таблиц, должны выполняться одновременно в транзакции.LastModifiedDate
Поле будет добавлено вAnimal
таблицу и все таблицы подкласса. Это поле обновляется только в том случае, если обновляется эта конкретная таблица: если обновление происходит в конкретном случае ,AnimalCat
но не вAnimal
немAnimalID
, то будет установлено толькоLastModifiedDate
поле вAnimalCat
.источник
D
, поэтому я хотел применить метод из вашего ответа. Два объекта имеют общий атрибут,E
которого нет в третьем объекте. Должен ли я игнорировать этот факт и применять стандартное решение, или есть способ дальнейшей оптимизации моего дизайна?Во-первых, у вас хорошо получается различать ER-моделирование и реляционное моделирование. Многие новички не делают.
Вот несколько модных слов, которые вы можете использовать для поиска полезных статей в Интернете.
Ваш случай - классический случай класса / подкласса или, если хотите, тип / подтип.
Фраза, которая используется в моделировании ER, является «обобщением / специализацией». И многие статьи показывают это в рамках модели, называемой EER (Enhanced Entity-Relationship). Этого не было в первоначальной презентации Питера Чена по моделированию ER. Это было добавлено позже. Для довольно хорошего резюме поколения / спецификации в формате PDF, нажмите здесь
Затем, при преобразовании случая класса / подкласса в реляционное моделирование вы разрабатываете таблицы. Существует более одного подхода. Два основных подхода называются наследованием отдельных таблиц и наследованием таблиц классов. У каждого есть свои преимущества и недостатки. Лучшая презентация этих двух проектов - от Мартина Фаулера. Вы можете увидеть его схему здесь и здесь .
Большим преимуществом наследования отдельных таблиц является простота. Все это хранится в одной таблице. Большой недостаток - много NULL. Это может тратить пространство и время и привести к запутанной логике.
Наследование таблиц классов требует соединений, но они просты и быстры. Особенно, если вы используете метод, называемый общим первичным ключом, в котором PK в таблицах подклассов является копией PK в таблице суперкласса. Вы можете создавать представления для каждого подкласса, которые объединяют данные суперкласса с данными подкласса.
Наконец, в этой области есть тег, который собирает вопросы, подобные вашему.
Вот оно: подтипы
источник
Я вижу на возможном дизайне как
Таблица
Race
Таблица
Breed
Таблица
Animal
Эти PK выше будут автоматически увеличивать столбец. Другие столбцы в
Animal
таблице могут быть названы соответственно.источник
Ваш нынешний метод неплох. Однако, если вы собираетесь добавить больше рас (птиц, рыб и т. Д.), То создание отдельной таблицы для каждой из них может быть затруднительным. Я бы порекомендовал что-то вроде следующего:
Порода, на мой взгляд, должна иметь только одну расу. Поэтому, если вы сохраните породу в таблице Animal, вы сможете определить расу, присоединившись к таблице Breed. Очевидно, добавьте любые другие атрибуты (имя, описание и т. Д.) В таблицы породы и расы по мере необходимости.
источник