Вы можете сделать это с помощью простой схемы плюс общее ограничение базы данных, если ваша СУБД поддерживает их (и в результате производительность будет терпимой).Большинство, к сожалению, этого не делают.
Кроме того, самый чистый подход - это дублирование внешних (супер) ключей.Вот реляционный подход с псевдокодом, который не требует NULL;типы данных и неинтересные атрибуты опущены:
create table Task {
TaskId,
key { TaskId }
};
create table Owner {
OwnerId,
key { OwnerId }
};
create table TaskOwner { /* Bog standard association table */
TaskId,
OwnerId,
key { Taskid, OwnerId }
reference TO_T { TaskId } references Task { TaskId },
reference TO_O { OwnerId } references Owner { OwnerId }
};
create table TaskGroup {
GroupId,
OwnerId,
key { GroupId }, /* Each group has exactly one owner */
reference TG_O { OwnerId } references Owner { OwnerId }
};
create table TaskGroupTask {
TaskId,
GroupId,
OwnerId,
key { TaskId }, /* Each task may belong to at most one group */
reference TGT_TO { TaskId, OwnerId } references TaskOwner { TaskId, OwnerId },
/* Foreign superkey coming up */
reference TGT_TG { GroupId, OwnerId } references TaskGroup { Group, OwnerId }
};
Подсказка в том, что TaskGroupTask.Ownerid
выполняет двойную функцию как часть ссылок на TaskOwner
и TaskGroup
и тем самым гарантирует, что владелец группыидентичен владельцу каждой задачи в нем.Здесь есть иностранный суперключ - TGT_TG
относится к надмножеству ключа TaskGroup
, но если ваша СУБД возражает против этого, возможный обходной путь - создать (лишний) уникальный индекс для надмножества.
Наличие отдельной таблицы TaskGroupTask
вместо обнуляемого атрибута TaskOwner.GroupId
на первый взгляд может показаться излишним, но оно позволяет использовать простое ограничение ключа для применения правила, согласно которому задача может принадлежать не более чем одной группе.Кроме того, он избегает значений NULL.
Существует функциональная зависимость { GroupId } -> { OwnerId }
в TaskGroupTask
, которая нарушает нормальную форму Бойса-Кодда, но избыточность контролируется ссылкой TGT_TG
, и необходимо применятьправила ситуации.
Смена владельца группы (и всех ее задач) включает обновление трех таблиц в одной и той же выписке / транзакции, но у правильной СУБД с этим не должно быть проблем.
Этот дизайн позволяет заданию принадлежать нескольким владельцам и быть в одной группе одновременно, создавая ситуацию, когда все задания в группе принадлежат одному владельцу, но они принадлежат другим владельцам (хотя не группы) так же.Из вашего вопроса неясно, если это проблема, поэтому дайте мне знать, если это так.Дизайн также запрещает группы без владельцев, но я предполагаю, что это нормально.