我有一个汽车表和司机表。每辆车可以由一些驾驶员驾驶,但其中必须有一名驾驶员是活跃驾驶员,并且每个驾驶员只能驾驶一辆车。我需要查询活跃的驾驶员,并且需要找到驾驶员可以驾驶的汽车,无论他是否活跃。我应该如何设计表格和约束?我互相FK,但感觉不正确。
最佳答案
这是一个很难使用数据库约束来管理的问题。您可以在 CAR 表中放置一个指向 DRIVER 的外键列,并在 DRIVER 中放置一个指向 CAR 的外键列,但这并不能保证每辆车和驾驶员都指向对方。
原始建议:
仅使用数据库约束(即没有过程代码)来强制执行此操作的唯一方法是创建第三个表,如下所示:
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:简化/关注点分离:
保罗评论说,由于历史与当前任务的混合,我最初的建议很复杂。我同意这一点。在我发布解决方案后,这实际上一直困扰着我。在我看来,最好的方法是满足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_ASSIGNMENT 中进行每次插入或更新并在 DRIVER_ASSIGNMENT_HISTORY 中创建插入的代码。这可以创建为数据库触发器,在这种情况下,应用程序仍然不需要过程代码,并且所有内容都可以包装在一个整洁的事务中以保持所有内容的一致性。
关于database-design - 一对一和一对多在一起如何设计?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5520218/