2012-06-29 37 views
1

完整問題:

從一個子表使用外鍵鏈接到其祖父表中的某一行的子表(引用祖父母主鍵),是否可以使用子表的複合外鍵中引用的祖父行中的字段鍵?是否可以在子表的複合外鍵中使用引用(通過外鍵)祖父行的字段?

我目前的數據庫設計有一個主父表,項目項目有兩個子表,JobTitles任務任務然後有一個子表子任務子任務然後有一個子表作業,這是一個x-ref表,將僱員放在子任務。我遇到的問題是分配JobTitles作業; JobTitles屬於項目,並且在任何給定的項目這樣的分配應該只能夠引用JobTitles共享項目。我最近問this question有關限制選擇JobTitle共享項目的人。然而,從那以後,我發現一個複合外鍵是一個更清潔的解決方案。

簡單的數據庫佈局:

  • 項目
    • JobTitles
    • 任務
      • 子任務
        • 分配

我已經找到了如何創建一個複合鍵here,但對於這個,我需要使用項目的主鍵作爲複合外鍵的一部分。

表:

  • 項目
    • 項目名(PK)
    • 專案編號(唯一索引)
  • JobTitles
    • 喬BTITLE
    • 專案編號(外鍵 - > Projects.ProjectID)(複合PK:JOBTITLE-專案編號)
    • JobTitleID(唯一索引)
  • 任務
    • TASKNAME
    • 專案編號(外鍵 - > Projects.ProjectID)(Composite PK:TaskName-ProjectID)
    • TaskID(Uni闕指數)
  • 子任務
    • SubtaskName
    • 的TaskID(外鍵 - > Tasks.TaskID)(複合PK:SubtaskName-的TaskID)
    • SubtaskID(唯一索引)
  • 作業
    • 僱員(外鍵)
    • SubTaskID(外鍵 - > Subtasks.SubtaskID)(複合PK:僱員-SubtaskID)
    • JobTitleID(外鍵 - > JobTitles.JobTitleID)
    • AssignmentID(唯一索引)

爲了一個JOBTITLE分配到分配,我想建立使用分配的專案編號(從其父任務)和其選定的JobTitleID複合外鍵。唯一的問題是,我不知道如何獲取兩代之外的ProjectID,以用於密鑰。可以通過將每個世代的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 UPDATE觸發器Assignments,它們引發錯誤以拒絕包含無效Job_Title的數據。但是,您還需要在JobTitles上創建觸發器來處理引用記錄更改或刪除的情況;然後在其他所有可能導致聯繫中斷的表格上。醜陋難看醜陋。

因此,我的偏好是與上面給出的第一種方法。

+0

是的,如果我不能直接訪問ProjectID,那麼這絕對是最好的方法。我真的很喜歡遞歸任務的想法(我最近才學會使用實際的標識索引作爲PK而不是ID字段),但任務佈局是靜態的(總是project-> task-> subtask,不多/少)。謝謝你的幫助! – PeaBucket