Ваша проблема связана с понятием кардинальности отношений.Все отношения имеют некоторую мощность, которая выражает потенциальное число экземпляров на каждой стороне отношения, которые являются его членами или могут участвовать в одном экземпляре отношения.Например, для людей (для большинства живых существ, я полагаю, за редкими исключениями) отношение родителей и детей имеет кардинальное значение 2 to zero or many
, что означает, что для родительской стороны требуется два родителя, и может быть ноль илимногие дети (возможно, это должно быть 2 to 1 or many
)
В дизайне базы данных, как правило, все, что имеет 1 (один), (или ноль или один) на одной стороне, может быть легко представлено только двумятаблицы, по одной для каждой сущности (иногда требуется только одна таблица, см. примечание **) и столбец внешнего ключа в таблице, представляющий сторону «многие», который указывает на другую таблицу, содержащую сущность на стороне «один».
В вашем случае у вас есть many to many
отношения.(Задача может иметь несколько предшественников, и каждый предшественник, безусловно, может быть предшественником для нескольких задач). В этом случае требуется третья таблица, где каждая строка, по сути, представляет связь между двумя задачами, представляя, что одна является предшественницейДругой.Как правило, эта таблица предназначена для того, чтобы содержать только все столбцы первичных ключей двух родительских таблиц, а ее собственный первичный ключ представляет собой совокупность всех столбцов в обоих родительских первичных ключах.В вашем случае он просто имеет два столбца, taskId и PredecessorTaskId, и эта пара идентификаторов должна быть уникальной в таблице, чтобы вместе они образовывали составной PK.
При запросах, чтобы избежать двойного подсчета столбцов данныхв родительских таблицах, когда есть несколько объединений, просто основывайте запрос на родительской таблице ... например, чтобы найти продолжительность самого длинного родителя, предполагая, что ваша таблица ассоциации называется TaskPredecessor
Select TaskId, Max(P.Duration)
From Task T Join Task P
On P.TaskId In (Select PredecessorId
From TaskPredecessor
Where TaskId = T.TaskId)
**НОТА.В тех случаях, когда оба объекта в отношении имеют один и тот же тип объекта, они оба могут находиться в одной и той же таблице.Каноническим примером (luv that word) является таблица сотрудников с отношением «многие к одному» между работником и руководителем ... Поскольку руководитель также является сотрудником, как работники, так и руководители могут быть в одной таблице [Сотрудник] и в сфере отношенийМожно смоделировать с помощью внешнего ключа (называемого, скажем, SupervisorId), который указывает на другую строку в той же таблице и содержит идентификатор записи сотрудника для руководителя этого сотрудника.