Mysql 具有时间间隔的M:N表的数据库设计
我想问你一个设计问题: 我正在设计一个让我挠头的桌子,不确定最好的方法是什么,我觉得我错过了一些东西: 有两个表A和B,它们之间有一个M:N关系表。关系表现在具有以下值: A.ID,B.ID,From,To 业务要求: 在任何时候,A:B关系只能是1:1 A:B可以按From和To datetime值定义的时间重复,这两个值指定了一个间隔 例如:汽车/司机。 任何一辆车在任何时候都只能有一名司机 任何驾驶员在任何时候只能驾驶一辆车(这不是topgear,好吗?:) 司机可以在一段时间后换车,也可以回到同一辆车上 现在,我不确定: -我应该和什么一起去?A、 B是不够的,添加From和To感觉不对,可能是一个自动增量PK? -有没有办法通过DB设计来强化业务需求? -出于商业原因,我不希望它出现在历史表格中。为什么?好吧,让我们假设这辆车是租来的,我想知道,给定一个日期,谁在那个日期租了什么车。将其拆分为历史表将需要更多的joinst:( 我觉得我错过了一些东西,一些一般的模式…或者我不知道Mysql 具有时间间隔的M:N表的数据库设计,mysql,sql,Mysql,Sql,我想问你一个设计问题: 我正在设计一个让我挠头的桌子,不确定最好的方法是什么,我觉得我错过了一些东西: 有两个表A和B,它们之间有一个M:N关系表。关系表现在具有以下值: A.ID,B.ID,From,To 业务要求: 在任何时候,A:B关系只能是1:1 A:B可以按From和To datetime值定义的时间重复,这两个值指定了一个间隔 例如:汽车/司机。 任何一辆车在任何时候都只能有一名司机 任何驾驶员在任何时候只能驾驶一辆车(这不是topgear,好吗?:) 司机可以在一段时间后换车,也可
谢谢你的帮助,所以谢谢你:)我不认为你错过了什么。我想你已经掌握了问题所在 我读过几篇关于如何在关系数据库中处理“时态”数据的文章 基本共识是,传统的关系模型没有任何内置机制来支持时态数据 有几种方法,有些方法比其他方法更适合特定的需求,但所有这些方法都感觉像是“管道胶带” (我本想说“上紧了”,但我想在红绿灯的帽尖处是这样的:“……杂务工的秘密武器,管道胶带”,以及“如果女人们觉得你不帅,她们至少应该觉得你很在行。”)
对于表的主键或唯一键,您可以使用
(a\u id,b\u id,from)的组合。这将为该行提供一个唯一标识符
但是,这并不能防止“时间”范围重叠
MySQL表没有声明性约束,可以防止存储为“开始”、“结束”或“开始”、“持续时间”等的日期时间范围“重叠”。(至少,在一般情况下。如果您有非常明确的范围,并且触发器将从
四舍五入到甚至四小时的边界,并且持续时间精确到四小时,则可以使用唯一约束。在更一般的情况下,对于从
和到
的任何ol'值,唯一约束对u不起作用。)美国
CHECK
约束是不够的(因为您需要查看其他行),即使可能,MySQL实际上也不会强制执行CHECK约束
(据我所知)让数据库强制执行此类约束的唯一方法是使用触发器
,它查找是否存在受影响(插入/更新)行冲突的另一行
插入前需要一个触发器,更新前需要一个触发器。触发器需要查询表,以检查是否存在与新的/修改的行“重叠”的行
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) >
选择1
来自MyT表
其中t.a_id=新的a_id
t.b_id=新的b_id
和t
和<(t.from,t.to)重叠(NEW.from,NEW.to)>
显然,最后一行是所需实际语法的伪代码
之前的行只需要在更新之前的触发器中使用,因此我们找不到(作为“匹配”)正在更新的行。那里的实际检查实际上取决于主键(或唯一键)的选择
在MySQL 5.5中,如果发现新的/更新的行会违反约束,我们可以使用SIGNAL
语句返回错误。在MySQL的早期版本中,我们可以通过执行导致实际错误发生的操作来“抛出”错误,例如对已知不存在的表名运行查询
最后,这种类型的功能不一定要在数据库触发器中实现;这可以在客户端处理。三个表如何:
TCar、TDriver、TLog
TCar
pkCarID
FKDridrid
名字
一个独特的司机索引确保司机只在一辆车里。转动外键
我们的关系是1:1
河
pkDriverID
名字
TLog
pkLogID(代理pk)
fkCarID
FKDridrid
从…起
到
通过2个连接,您将获得您描述的任何信息。如果您只需要通过driverID或cardid查找汽车数据,您只需一个连接即可。感谢大家的输入,到目前为止,我正在考虑此方法,如果您有任何批评/指出缺陷,我将不胜感激:
表(伪sqlcode):
当然,CarID是FK-to-Car(ID),DriverID是FK-to-Driver(ID)
下一个阶段是两个触发器(我希望这可以在mysql中完成(在MSSQL上工作,但我现在手头没有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;
create trigger Assignment\u分配时更新,而不是更新为
删除分配
从分配
连接插入
on(inserted.CarID=Assignment.CarID
或插入。DriverID=Assignment.DriverID)
和(inserted.CarID omem.CarID或inserted.DriverID omem.DriverID)
插入到分配中
选择*从插入;
创建触发器分配\u在删除后插入分配作为
在作业历史记录中插入
从删除中选择CarID、DriverID、from、NOW();
我测试了一个bi
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;