Database design 一对一和一对多结合在一起如何设计?

Database design 一对一和一对多结合在一起如何设计?,database-design,one-to-many,one-to-one,Database Design,One To Many,One To One,我有一张汽车桌和司机桌。每辆车都可以由一些驾驶员驾驶,但其中一人必须是主动驾驶员,并且每个驾驶员只能驾驶一辆车。我需要查询活跃的司机,我需要找到一个司机可以驾驶的汽车,即使他是活跃的或没有。我应该如何设计表格和结构?我把FK放在一起,但感觉不对 这是一个很难使用数据库约束进行管理的问题。您可以将外键列放在汽车表中,指向驾驶员,将外键放在驾驶员中,指向汽车,但这不能保证每辆汽车和驾驶员都指向对方 原始建议: 仅使用数据库约束(即无过程代码)强制执行此操作的唯一方法是创建第三个表,如下所示: DRI

我有一张汽车桌和司机桌。每辆车都可以由一些驾驶员驾驶,但其中一人必须是主动驾驶员,并且每个驾驶员只能驾驶一辆车。我需要查询活跃的司机,我需要找到一个司机可以驾驶的汽车,即使他是活跃的或没有。我应该如何设计表格和结构?我把FK放在一起,但感觉不对

这是一个很难使用数据库约束进行管理的问题。您可以将外键列放在汽车表中,指向驾驶员,将外键放在驾驶员中,指向汽车,但这不能保证每辆汽车和驾驶员都指向对方

原始建议:

仅使用数据库约束(即无过程代码)强制执行此操作的唯一方法是创建第三个表,如下所示:

DRIVER_ASSIGNMENT
( car_id int not null
, driver_id int not null 
, start_time datetime not null
, end_time datetime not null
, primary key (car_id, driver_id, start_time)
, unique key (car_id, start_time)
, unique key (driver_id, start_time)
)
这样,每辆车只能有一名驾驶员,而每个驾驶员(一次)只能有一辆车。如果您真的想变得有趣,您还可以定义检查约束,以确保同一驱动程序的两个指定在时间上不会重叠

编辑:在此模式中,某些汽车和某些驾驶员可能未分配,但不能过度分配。 编辑2:根据OP关于一段时间内需要多个作业的新评论

编辑3:简化/分离关注点:

Paul评论说,我最初的建议很复杂,因为历史和当前任务混在一起。我同意这一点。实际上,在我发布解决方案后,这件事一直困扰着我。在我看来,最好的方法是满足OP的要求,即在任何时候将一辆车和一名驾驶员映射在一起-仅使用数据库约束,而不诉诸程序性业务规则代码来强制执行基数,同时规定了跟踪谁在何时驾驶哪辆车的要求

因此,我将修改设计,使用两个单独的表格,如下所示:

DRIVER_ASSIGNMENT
( car_id int not null
, driver_id int not null 
, start_time datetime not null default GETDATE
, primary key (car_id, driver_id)
, unique key (car_id)
, unique key (driver_id)
)

DRIVER_ASSIGNMENT_HISTORY
( car_id int not null
, driver_id int not null 
, start_time datetime not null
, end_date datetime not null  -- This is optional. It is nice to have but not necessary.
, primary key (car_id, driver_id, start_time)
)

使用此模式,驾驶员和车辆可以一次一对地配对,但这些配对的历史记录会被跟踪。DRIVER_ASSIGNMENT(驾驶员分配)表强制执行基数,DRIVER_ASSIGNMENT_HISTORY(驾驶员分配历史)表提供查看谁在驾驶什么以及何时驾驶的功能。您必须编写的唯一程序代码是在驱动程序分配中进行每次插入或更新并在驱动程序分配历史中创建插入的代码。可以将其创建为数据库触发器,在这种情况下,应用程序仍然不需要过程代码,并且可以将所有内容包装在一个整洁的事务中,以保持所有内容的一致性。

要管理这些要求,我建议以以下方式使用:

Driver > Table
    Id  - pkey
    ... other fields

CarDriver > Junction Table
    DriverId - part 1 composite pkey, foreign key to Driver.Id
    CarId - part 2 composite pkey, foreign key to Car.Id

Car > Table
    Id - pkey
    ActiveDriverId - foreign key to Driver.Id
    ... other fields

Car表中的CurrentDriverId字段将指示当前驾驶员,而CarDriver交叉表将显示哪些驾驶员可以驾驶哪些车辆。请注意,维护所需信息和状态所需的字段非常少。

您可以发布您尝试的内容以及关注的原因吗?“主动驾驶员”和“驾驶员”之间有区别吗?所有驾驶员都必须驾驶一辆车吗?或者有些司机可能没有车(也就是说,是乘客)?@Galz我也必须了解活跃的司机。这与我的建议非常相似,只是我不知道如何防止连接表变成多对多,我也不清楚你为什么将CurrentDriverID放在车表中。是什么使它与CarDriver保持同步?连接表旨在干净地促进多对多关系。ActiveDriverId与连接表无关。它奇异地指示当前驱动器。请注意,这是一个fkey to Driver。您的驱动程序分配确实符合连接表的概念,但过于复杂。你似乎还把它做成了一个日志表,时间值被用来确定当前的驾驶员……保罗,这不是一个多对多的问题,因为一个驾驶员只能驾驶一辆车。保罗对我的建议的复杂性提出了一个很好的观点。我已经相应地修改了它(编辑3)。