SQL 3个表之间的多对多关系

时间:2014-02-19 13:55:07

标签: sql many-to-many foreign-key-relationship

我有以下表格:

Users
 - user_id (PK)

Projects
 - project_id (PK)

Tasks
 - taks_id (PK) 
 - project_id (FK)

要求是:

  • 每个任务只属于一个项目。
  • 每个项目都有一个或多个用户。
  • 每个任务有0个或更多用户(但用户必须属于该任务所属的项目)。

我目前正在尝试使用2个连接表执行上述操作:

UsersProjects
[user_id]    INT           NOT NULL,
[project_id] INT           NOT NULL,
[accepted] BIT NULL, 
FOREIGN KEY ([user_id]) REFERENCES [dbo].[_Users] ([user_id]),
FOREIGN KEY ([project_id]) REFERENCES [dbo].[_Projects] ([project_id]), 
CONSTRAINT [PK_UsersProjects] PRIMARY KEY ([user_id], [project_id])

UsersTasks
[user_id]    INT           NOT NULL,
[task_id] INT           NOT NULL,
[accepted] BIT NULL, 
FOREIGN KEY ([user_id]) REFERENCES [dbo].[_Users] ([user_id]),
FOREIGN KEY ([task_id]) REFERENCES [dbo].[_Tasks] ([task_id]), 
CONSTRAINT [PK_UsersTasks] PRIMARY KEY ([user_id], [task_id])

我是否在正确的轨道上寻找多对多的关系和要求? 我该如何优化呢?

感谢您花时间阅读本文!

1 个答案:

答案 0 :(得分:1)

  

每个任务有0个或更多用户(但用户必须属于该任务所属的项目)。

我假设您正在询问如何强制执行此最后一个约束 - 它不在您当前的数据库架构中。我看到两个选择:

  1. 您必须通过SQL执行此操作(例如,当您将记录插入UsersTasks时,您在UsersProjects JOIN任务上发出SELECT以查看是否至少有记录匹配)
  2. 您可以更改任务主键的结构。即你创建一个PK作为复合(Project_ID + Task_ID),然后Task_ID不再是一个身份字段,而是从例如每个新项目1个。然后用户UsersTasks的PK也变为User_ID + Project_ID + Task_ID,然后您可以直接引用完全FK到UserProjects(User_ID + Project_ID)。它不如解决方案1那么直观,但是工作并且不需要自定义SQL来强制执行完整性。
  3. 对于选项2:

    任务的约束略有不同

    ...
    CONSTRAINT [PK_Tasks] PRIMARY KEY ([project_id], [task_id])
    
    UsersTasks
    [user_id]    INT           NOT NULL,
    [project_id] INT        NOT NULL,
    [task_id] INT           NOT NULL,
    [accepted] BIT NULL, 
    FOREIGN KEY ([user_id]) REFERENCES [dbo].[_Users] ([user_id]),
    FOREIGN KEY ([project_id], [task_id]) REFERENCES [dbo].[_Tasks] ([project_id],[task_id]), 
    FOREIGN KEY ([user_id], [project_id]) REFERENCES [dbo].[_User_Projects] ([user_id],[project_id]), 
    CONSTRAINT [PK_UsersTasks] PRIMARY KEY ([user_id], [project_id], [task_id])