Один ко многим самому себе - PullRequest
5 голосов
/ 02 октября 2008

Как можно структурировать таблицу для сущности, которая может иметь отношение один ко многим к себе? В частности, я работаю над приложением для отслеживания разведения животных. У каждого животного есть удостоверение личности; у него также есть идентификатор производителя и идентификатор дамы. Таким образом, возможно иметь одного ко многим от отца или дамы до его потомства. Я был бы склонен к чему-то вроде этого:

ID INT NOT NULL PRIMARY KEY
SIRE_ID INT 
DAME_ID INT

и запишите нулевое значение для тех животных, которые были приобретены и добавлены к племенному скоту, и идентификатор в таблице для остальных.

Итак:

  1. Может кто-нибудь указать мне на статья / веб-страница, которая обсуждает моделирование такого рода отношений?
  2. Должен ли идентификатор быть INT или каким-то другим строки? NULL в INT будет указывают на то, что животное не имеет родители в базе данных, но строка со специальными значениями флага может быть используется для обозначения того же самого.
  3. Будет ли это лучше всего смоделировано через две таблицы? Я имею ввиду одну таблицу для животных и отдельный таблица с указанием родства e. g.:

    Animal

    ID INT НЕ НУЛЬ ПЕРВИЧНЫЙ КЛЮЧ

    Родство

    ID INT НЕ НУЛЬ ПЕРВИЧНЫЙ КЛЮЧ ИНОСТРАННЫЙ КЛЮЧ

    SIRE_ID INT ПЕРВИЧНЫЙ КЛЮЧ ИНОСТРАННЫЙ КЛЮЧ

    DAME_ID INT ПЕРВИЧНЫЙ КЛЮЧ ИНОСТРАННЫЙ КЛЮЧ

Прошу прощения за вышесказанное: мой SQL ржавый. Я надеюсь, что это как бы передает то, о чем я думаю.

Ответы [ 9 ]

6 голосов
/ 02 октября 2008

Ну, это "нормальное" отношение один ко многим, и метод, который вы предлагаете, является классическим для его решения.

Обратите внимание, что две таблицы денормализованы (я не могу точно указать, где находится часть "супер-ключ-не-хорошо-должен-быть-подмножество-другого-ключа-fsck-I-забыл", но я ' я уверен, что он где-то есть); Интуитивно понятная причина заключается в том, что кортеж в первом соответствует максимум кортежу во втором, поэтому, если у вас нет большого количества животных с нулевыми идентификаторами отца и дам, это не очень хорошее решение в любой перспективе (это ухудшает производительность - нужно объединение - и не уменьшает требования к хранилищу).

4 голосов
/ 02 октября 2008

Я думаю, что ваш макет с использованием только одной таблицы в порядке. Вы определенно хотите сохранить 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)

3 голосов
/ 02 октября 2008

Я задавал похожий вопрос несколько месяцев назад на сайте MySQL. Я бы рекомендовал вам взглянуть на ответ, который я получил от Питера Броули относительно этого типа отношений: http://forums.mysql.com/read.php?135,187196,187196#msg-187196

Если вы хотите продолжить изучение этой темы, я бы порекомендовал вам взглянуть на древовидные иерархии в Википедии.

Альтернативная предлагаемая архитектура (которая будет полностью нормализована) будет выглядеть примерно так:

Таблица: животное

ID | Имя | Порода

Таблица: родословная

animal_id | parent_id | parentType (сир или дама)

1 голос
/ 02 октября 2008

Я не знаю о животноводстве, но, похоже, ваш 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] .ather вернет myAnimal. .Parent [] может быть коллекцией двух его родителей, которая должна работать, если [0] всегда один из родителей (отец), а [1] всегда другой (мать).

Сделайте ID идентификатором PK и назначьте Sire_ID и Dame_ID программно, возвращая идентификаторы его родителей. Никакие связи с внешним ключом не должны быть необходимыми, хотя оба родительских идентификатора могут ссылаться обратно на идентификатор, если вы действительно этого хотите.

1 голос
/ 02 октября 2008

INT - лучший выбор для столбца ID и лучше подходит, если вам нужно использовать последовательность для генерации уникальных идентификаторов.

Я не вижу никакой выгоды в разделении дизайна на две таблицы.

0 голосов
/ 02 октября 2008

Похоже, вы хотите построить что-то вроде дерева.

Как насчет чего-то вроде?:

 ID          Primary Key,
 Parent_ID   Foreing_Key
 ( data )

Существует некоторая функциональность для выполнения запросов в таблицах, имеющих отношение к себе. См. Синтаксис Соединение по : http://www.adp -gmbh.ch / ora / sql / connect_by.html

0 голосов
/ 02 октября 2008

Я думаю, что, поскольку ясно, что у животного есть только один отец и одна плотина, использование единой таблицы имело бы смысл. Я предпочитаю использовать int или bigint в качестве идентификатора строки с нулевым значением, означающим отсутствие связи. Тогда я бы, вероятно, использовал какой-то другой метод для уникальной идентификации животных, чтобы они не попадали в таблицу дважды, а также для создания уникального индекса по этому столбцу.

0 голосов
/ 02 октября 2008

На самом деле это не отношения один ко многим, если только у животного не может быть много родителей.

Я бы оставил его в виде единой таблицы с уникальным идентификатором ключа для животного, одним целым полем для каждого из родителей и, вероятно, текстовым полем для общих заметок о животном, например, где оно было куплено, если это дело.

0 голосов
/ 02 октября 2008

Используйте предложение "connect by" с SQL, чтобы указать, какой иерархии следовать.

...