2012-06-29 2 views
1

Полный Вопрос:

С ребенком таблицы, связанной со строкой в ​​его прародителя таблицы внешний ключ (ссылки прародитель первичный ключ), можно использовать поле из ссылочного прародителя строки в композитной чуждого дочернего стола ключ?Возможно ли использовать поле из строки grandparent по ссылке (через внешний ключ) в составном внешнем ключе дочерней таблицы?

В моей текущей базе данных есть основная родительская таблица, Проекты. Проекты имеет два детских стола, Рабочие места и Задачи. Задачи затем имеет детский стол Подзадачи. Подзадачи затем имеет детский стол Задания, который представляет собой таблицу x-ref, служащую сотрудниками на Подзадачи. Проблема, которую я придумал, заключается в назначении JobTitles - Задания; JobTitles принадлежит проекту, и как таковой Подборки при любом данных проекте должен только быть в состоянии ссылаться JobTitles, которые разделяют проект. Недавно я спросил this question относительно ограничения выбора JobTitle тем, кто использует проект. Однако с тех пор я нашел сложный внешний ключ, чтобы быть более чистым решением.

Простой макет базы данных:

  • Проекты
    • JobTitles
    • Задачи
      • подзадач
        • Задания

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

Таблицы:

  • Проекты
    • ProjectName (PK)
    • ProjectID (уникальный индекс)
  • JobTitles
    • Jo BTITLE
    • ProjectID (Foreign Key -> Projects.ProjectID) (Composite PK: JobTitle-ProjectID)
    • JobTitleID (уникальный индекс)
  • Задачи
    • TaskName
    • ProjectID (Внешний ключ -> Projects.ProjectID) (Композитный ПК: TaskName-ProjectID)
    • TaskID (Uni Индекс дие)
  • подзадачи
    • SubtaskName
    • TaskID (Foreign Key -> Tasks.TaskID) (Composite PK: SubtaskName-TaskID)
    • SubtaskID (уникальный индекс)
  • Задания
    • EmployeeID (Foreign Key)
    • SubTaskID (Foreign Key -> Subtasks.SubtaskID) (Composite PK: EmployeeID-SubtaskID)
    • JobTitleID (Foreign Key -> JobTitles.JobTitleID)
    • AssignmentID (уникальный индекс)

для того, чтобы назначить JobTitle к уступке, я хочу, чтобы создать составной внешний ключ с помощью присвоения в ProjectID (от родительского Task) и его выбранной JobTitleID. Единственная проблема заключается в том, что я понятия не имею, как захватить ProjectID, который находится на расстоянии двух поколений, для использования в ключе. Можно было бы передать ProjectID вниз через каждое поколение, обернув его составным ключом в каждой таблице, но составные клавиши не могут что-то бросать вокруг волей-неволей, учитывая то, что они берут на себя производительность (не говоря уже о передаче значения вниз кажется немного неряшливым). Есть ли способ добраться до ProjectID для использования в ключе, не передавая его через другие таблицы?

ответ

2

Как вы говорите, вы можете передать ProjectID по каждой таблице. Я не думаю, что это небрежно, и это позволяет создавать составные первичные ключи, которые позволяют повторно использовать, например. TaskID для разных проектов. Как только кто-то осознает это, можно заметить, что обычная практика использования столбцов ID в каждом столе немного лишнее.вместо этого можно использовать семантически значимые данные в качестве ключей, которые, как правило, мое предпочтение (уверен, что это более дорогостоящим с точки зрения пространства, но результаты индексации в относительно мало влияет на время):

CREATE TABLE Projects (
    ProjectName VARCHAR(20) NOT NULL PRIMARY KEY 
); 

CREATE TABLE JobTitles (
    ProjectName VARCHAR(20) NOT NULL, 
    JobTitle VARCHAR(20) NOT NULL, 
    PRIMARY KEY (ProjectName, JobTitle), 
    FOREIGN KEY (ProjectName) REFERENCES Projects (ProjectName) 
); 

CREATE TABLE Tasks (
    ProjectName VARCHAR(20) NOT NULL, 
    TaskName VARCHAR(20) NOT NULL, 
    ParentTask VARCHAR(20), 
    PRIMARY KEY (ProjectName, TaskName), 
    FOREIGN KEY (ProjectName) REFERENCES Projects (ProjectName), 
    FOREIGN KEY (ProjectName, ParentTask) REFERENCES Tasks (ProjectName, TaskName) 
); 

CREATE TABLE Assignments (
    ProjectName VARCHAR(20) NOT NULL, 
    TaskName VARCHAR(20) NOT NULL, 
    JobTitle VARCHAR(20) NOT NULL, 
    Email  VARCHAR(255) NOT NULL, 
    PRIMARY KEY (ProjectName, TaskName, JobTitle), 
    FOREIGN KEY (ProjectName) REFERENCES Projects (ProjectName), 
    FOREIGN KEY (ProjectName, TaskName) REFERENCES Tasks (ProjectName, TaskName), 
    FOREIGN KEY (ProjectName, JobTitle) REFERENCES JobTitles (ProjectName, JobTitle), 
    FOREIGN KEY (Email) REFERENCES Employees (Email) 
); 

Поскольку MySQL не поддерживает более мощная проверка ограничений, единственная другая возможность, о которой я могу думать, заключается в определении BEFORE INSERT и BEFORE UPDATE триггеров на Assignments, которые вызывают ошибки для отклонения данных, содержащих недопустимый JobTitle. Однако тогда вам также понадобится создать триггеры на JobTitles для обработки ситуаций, когда такие ссылочные записи изменяются или удаляются; а затем и на всех других таблицах, которые могут вызвать разрыв в связи. Уродливые уродливые уродливые.

Следовательно, мое предпочтение отдается первому подходу, приведенному выше.

+0

Да, если я не могу получить доступ к ProjectID напрямую, это, безусловно, лучший способ сделать это. Мне очень нравится идея рекурсивных задач (я только недавно научился использовать фактический идентификационный индекс как PK вместо поля ID), но макет задачи является статическим (всегда project-> task-> subtask, не более/менее). Спасибо за вашу помощь! – PeaBucket

Смежные вопросы