我想问你一个设计问题:
我正在设计一张桌子让我头脑发热,不知道最好的方法是什么,我觉得我错过了一些东西:
它们之间有两个表A和B以及一个M:N关系表。关系表现在具有以下值: A.ID,B.ID,From,To
业务要求: 在任何时候,A:B关系船只能只有1:1 答:B可以按照From和To datetime定义的时间重复,这些值指定间隔
示例:汽车/司机。 任何车辆在任何时候都只能有1个车手 任何车手都可以随时开出一辆车(这不是顶级车,好吗?:)) 司机可以在一段时间后更换汽车,并可以返回同一辆车
现在,我不确定: - 我应该带什么PK? A,B是不够的,添加From和To感觉不对,也许是自动增量PK? - 通过数据库设计强制执行业务需求的方法吗? - 出于商业原因,我宁愿不在历史表中。为什么?好吧,让我们假设这辆车是租来的,我想知道,在约会的日期,谁拥有那天租用的汽车。将其拆分为历史表需要更多的连接:(
我觉得我错过了某种东西,某种普遍的模式......或者我不知道......
感谢任何帮助,谢谢:)
答案 0 :(得分:0)
我认为你实际上没有遗漏任何东西。我想你已经掌握了问题所在。
我读过几篇关于如何在关系数据库中处理“时态”数据的文章。
底线共识是传统的关系模型没有任何支持时态数据的内置机制。
有几种方法,有些方法比其他方法更适合特殊要求,但所有方法都感觉它们是“管道录音”。
(我打算说“狂奔”,但我认为在红色绿色的帽子的尖端是有序的:“......杂工的秘密武器,胶带”,“如果女人不发现你很帅,他们至少应该找到你方便的。“)
就表的PRIMARY KEY或UNIQUE KEY而言,您可以使用(a_id, b_id, from)
的组合。这将为行提供唯一标识符。
但是,这并不能阻止重叠的“时间”范围。
MySQL表没有声明性约束,可以防止“重叠”日期时间范围存储为“开始”,“结束”或“开始”,“持续时间”等。(至少在一般情况下。如果您有非常明确定义的范围,并且触发器将from
四舍五入到四小时的边界,并且持续时间精确到四小时,则可以使用UNIQUE约束。在更一般的情况下,对于任何ol'值from
和to
,UNIQUE约束对我们不起作用。
CHECK
约束是不够的(因为您需要查看其他行),即使可能,MySQL也不会实际执行检查约束。
让数据库强制实施这种约束的唯一方法(我知道)是TRIGGER
,它会查找受影响(插入/更新)行会发生冲突的另一行的存在。 / p>
您需要BEFORE INSERT
触发器和BEFORE UPDATE
触发器。触发器需要查询表,检查是否存在“重叠”新行/修改行的行
SELECT 1
FROM mytable t
WHERE t.a_id = NEW.a_id
AND t.b_id = NEW.b_id
AND t.from <> OLD.from
AND < (t.from, t.to) overlaps (NEW.from,NEW.to) >
显然,最后一行是伪代码,用于实际所需的语法。
之前的行仅在BEFORE UPDATE
触发器中需要,因此我们找不到(作为“匹配”)正在更新的行。那里的实际检查实际上取决于PRIMARY KEY
(或UNIQUE KEY
)(s)的选择。
使用MySQL 5.5,如果我们发现新的/更新的行会违反约束,我们可以使用SIGNAL
语句返回错误。使用以前版本的MySQL,我们可以通过执行导致实际错误发生的事情来“抛出”错误,例如针对我们知道不存在的表名运行查询。
最后,这种类型的功能不一定必须在数据库触发器中实现;这可以在客户端处理。
答案 1 :(得分:0)
三张桌怎么样: TCar,TDriver,TLog
TCAR pkCarID fkDriverID 名称
驾驶员的独特索引确保驾驶员只能驾驶一辆车。转动外键 fkDriverID成1:1的关系。
TDriver pkDriverID 名称
的TLog pkLogID(代理pk) fkCarID fkDriverID 从 到
通过2个连接,您将获得您描述的任何信息。如果你只是需要通过cardID找到carID数据或通过cardid找到驱动程序数据,你可以通过一个连接来完成。
答案 2 :(得分:0)
谢谢大家的意见,到目前为止,我正在考虑这种方法,感谢任何批评/指出缺陷: 表(pseudoSQLcode):
Car (ID pk auto_increment, name)
Driver(ID pk auto_increment, name)
Assignment (CarID unique,DriverID unique,from Datetime), composite PK (CarID,DriverID)
AssignmentHistory (CarID unique,DriverID unique,from Datetime,to Datetime) no pk
当然,CarID是FK到Car(ID),DriverID是FK到驱动程序(ID)
下一个阶段是两个触发器(和男孩哦男孩,我希望这可以在mysql中完成(适用于MSSSQL,但我现在没有一个mysql db方便测试):
!!!警告,MSSQL现在
create trigger Assignment _Update on Assignment instead of update as
delete Assignment
from Assignment
join inserted
on ( inserted.CarID= Assignment .CarID
or inserted.DriverID= Assignment .DriverID)
and ( inserted.CarID<> omem.CarID or inserted.DriverID<> omem.DriverID)
insert into Assignment
select * from inserted;
create trigger Assignment _Insert on Assignment after delete as
insert into Assignment_History
select CarID,DriverID,from,NOW() from deleted;
我测试了一下,似乎每个商务案例它都做我需要做的事情