Один ко многим самому себе
-
03-07-2019 - |
Вопрос
Как можно структурировать таблицу для сущности, которая может иметь отношение один ко многим сама с собой?В частности, я работаю над приложением для отслеживания разведения животных.У каждого животного есть идентификатор;у него также есть идентификатор отца и идентификатор матери.Таким образом, возможно иметь один ко многим от отца или матери к их потомству.Я был бы склонен к чему-то вроде этого:
ID INT NOT NULL PRIMARY KEY
SIRE_ID INT
DAME_ID INT
и запишите нулевое значение для тех животных, которые были куплены и добавлены в племенное поголовье, и идентификатор в таблицу для остальных.
Так:
- Может ли кто -нибудь указать мне на статью/веб -страницу, которая обсуждает моделирование таких отношений?
- Должен ли ID быть int или какой -то строкой?Нуль в INT указывает на то, что у животного нет родителей в базе данных, но для указания того же самого можно было бы использовать строку со специальными значениями флага.
Возможно, лучше ли это лучше смоделировать через две таблицы?Я имею в виду одну таблицу для животных и отдельная таблица исключительно, указывающая на родство e.г.:
Животное
ID INT NOT NULL ПЕРВИЧНЫЙ КЛЮЧ
Родство
ID INT NOT NULL ПЕРВИЧНЫЙ КЛЮЧ ВНЕШНИЙ КЛЮЧ
SIRE_ID INT ПЕРВИЧНЫЙ КЛЮЧ ВНЕШНИЙ КЛЮЧ
DAME_ID INT ПЕРВИЧНЫЙ КЛЮЧ ВНЕШНИЙ КЛЮЧ
Прошу прощения за вышесказанное:мой SQL заржавел.Надеюсь, это как-то передает то, о чем я думаю.
Решение
Что ж, это «нормальное» отношение «один ко многим», и предлагаемый вами метод является классическим для его решения.
Обратите внимание, что две таблицы денормализованы (я не могу точно указать, где находится часть «суперключ-не-хорошо-должно-быть-подмножеством-другого-ключа-fsck-я-забыл», но я почти уверен оно где-то есть);Интуитивная причина заключается в том, что кортеж в первом соответствует не более чем кортежу во втором, поэтому, если у вас нет большого количества животных с нулевыми идентификаторами отца и матери, это не является хорошим решением ни в какой перспективе (оно ухудшает производительность - необходимо соединение - и не снижает требования к объему памяти).
Другие советы
Я думаю, что ваш макет с использованием только одной таблицы подойдет.Вы определенно хотите, чтобы SIRE_ID и DAME_ID имели тот же тип данных, что и ID.Вы также хотите объявить их как ВНЕШНИЕ КЛЮЧИ (возможно, чтобы внешний ключ возвращался к той же таблице, и внешний ключ также может быть нулевым).
ID INT NOT NULL PRIMARY KEY
SIRE_ID INT REFERENCES TABLENAME (ID)
DAME_ID INT REFERENCES TABLENAME (ID)
Используя этот макет, вы можете легко найти родительских животных, а также построить дерево потомков для данного животного (для Oracle есть CONNECT BY).
Я задал аналогичный вопрос несколько месяцев назад на веб-сайте MySQL.Я бы порекомендовал вам взглянуть на ответ, который я получил от Питера Броули относительно этого типа отношений: http://forums.mysql.com/read.php?135,187196,187196#msg-187196
Если вы хотите глубже изучить эту тему, я бы порекомендовал вам изучить Древовидные иерархии в Википедии.
Альтернативная предлагаемая архитектура (которая будет полностью нормализована) будет выглядеть примерно так:
Стол:животное
Id | Имя | Порода
Стол:родословная
Animal_id | parent_id | Parenttype (сир или дама)
INT — лучший выбор для столбца ID и лучше подходит, если вам нужно использовать последовательность для создания уникальных идентификаторов.
Я не вижу никакой пользы в разбиении дизайна на две таблицы.
Я не разбираюсь в разведении животных, но похоже, что ваш Sire_ID — это отец, а Dame_ID — мать?Без проблем.Одна строка на животное, нулевые sire_ и dame_ID для купленных животных, проблем не предвижу.
[ID],[Sire_ID],[Dame_ID];
0,null,null (male)
1,null,null (female)
2,null,null (female)
3,0,1 (male)
4,0,2 (male)
5,null,null (female)
6,3,5
7,4,5
и так далее.Скорее всего, вы заполните TreeView или XmlNodeList в цикле while...
While (myAnimal.HasChildren) {
Animal[] children = GetChildren(Animal.ID)
for (int x=0; x<children.length; x++)
myAnimal.Children.Add(children[x]);
}
В данном случае Animal.Children — это коллекция животных.Следовательно, myAnimal.Children[0].Father вернет myAnimal..Parent[] может быть коллекцией двух своих родителей, что должно работать, пока [0] всегда является одним родителем (отцом), а [1] всегда является другим (матерью).
Сделайте ID Autonumber PK и программно назначьте Sire_ID и Dame_ID, вернув идентификаторы его родителей.Никакие отношения внешнего ключа не обязательны, хотя оба родительских идентификатора могут ссылаться на идентификатор, если вы действительно этого хотите.
Используйте предложение «connect by» в SQL, чтобы указать, какой иерархии следовать.
На самом деле это не связь «один ко многим», если только у животного не может быть много родителей.
Я бы оставил ее в виде одной таблицы с уникальным идентификатором ключа для животного, одним полем int для каждого из родителей и, возможно, текстовым полем, которое можно использовать для общих заметок о животном, например, где оно было куплено, если это так.
Я думаю, что, поскольку ясно, что у животного есть только один отец и одна мать, использование одной таблицы будет наиболее разумным.Я предпочитаю использовать int или bigint в качестве идентификатора строки, при этом нулевое значение означает отсутствие связи.Тогда я бы, вероятно, использовал какой-нибудь другой метод для уникальной идентификации животных, чтобы они не попадали в таблицу дважды, а также создал бы уникальный индекс для этого столбца.
Кажется, вы хотите построить что-то вроде дерева.
А как насчет чего-то вроде?:
ID Primary Key,
Parent_ID Foreing_Key
( data )
Есть некоторая функциональность для выполнения запросов к таблицам, имеющим отношения к самим себе.См. синтаксис Подключиться через: http://www.adp-gmbh.ch/ora/sql/connect_by.html