1

完全な質問:

外部キー (祖父母の主キーを参照) によって祖父母テーブルの行にリンクされている子テーブルから、子テーブルの複合外部キーで参照されている祖父母行のフィールドを使用できますか?

私の現在のデータベース設計には、メインの親テーブルProjectsがあります。Projectsには、 JobTitlesTasksという 2 つの子テーブルがあります。Tasksには子テーブルSubtasksがあります。Subtasksには子テーブルAssignmentsがあります。これは、従業員をSubtasksに配置する x-ref テーブルです。私が思いついた問題は、 JobTitlesAssignmentsに割り当てることです。JobTitlesはProjectに属しているため、特定のProjectAssignmentsは参照のみ可能である必要がありますProjectを共有するJobTitles。私は最近、 JobTitleの選択をプロジェクトを共有する人に制限することに関して、この質問をしました。しかし、それ以来、複合外部キーがはるかにクリーンなソリューションであることがわかりました。

シンプルなデータベース レイアウト:

  • プロジェクト
    • 役職
    • タスク
      • サブタスク
        • 課題

ここで複合キーを作成する方法を見つけましたが、そのためにはプロジェクトの主キーを複合外部キーの一部として使用する必要があります。

テーブル:

  • プロジェクト
    • プロジェクト名(PK)
    • ProjectID (一意のインデックス)
  • 役職
    • 職名
    • ProjectID (外部キー -> Projects.ProjectID) (複合 PK: JobTitle-ProjectID)
    • JobTitleID (ユニークインデックス)
  • タスク
    • タスク名
    • ProjectID (外部キー -> Projects.ProjectID) (複合 PK: TaskName-ProjectID)
    • TaskID (一意のインデックス)
  • サブタスク
    • サブタスク名
    • TaskID(外部キー -> Tasks.TaskID) (複合 PK: SubtaskName-TaskID)
    • SubtaskID (一意のインデックス)
  • 課題
    • EmployeeID (外部キー)
    • SubTaskID (外部キー -> Subtasks.SubtaskID) (複合 PK: EmployeeID-SubtaskID)
    • JobTitleID (外部キー -> JobTitles.JobTitleID)
    • AssignmentID (一意のインデックス)

JobTitle を Assignment に割り当てるために、Assignment の ProjectID (親 Task から) と選択した JobTitleID を使用して、複合外部キーを設定したいと考えています。唯一の問題は、キーで使用するために 2 世代離れた ProjectID を取得する方法がわからないことです。ProjectID を各テーブル内の複合キーにラップすることで、各世代に渡せる可能性がありますが、複合キーは、パフォーマンスにかかる負担を考慮すると、むやみに放り投げるものではありません (値を渡すことは言うまでもありません)ダウンは少しずさんなようです)。他のテーブルを通過せずに、キーで使用するために ProjectID を取得する方法はありますか?

4

1 に答える 1

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 はより強力な制約検証をサポートしていないため、私が考えることができる唯一の他のオプションは、無効な JobTitle を含むデータを拒否するエラーを定義BEFORE INSERTしてBEFORE UPDATEトリガーすることです。ただし、そのような参照レコードが変更または削除された状況を処理Assignmentsするには、トリガーも作成する必要があります。JobTitles次に、リンケージの中断を引き起こす可能性のある他のすべてのテーブルでも。醜い醜い。

したがって、私の好みは、上記の最初のアプローチです。

于 2012-06-29T14:58:13.467 に答える