在SQL中存储相关日期

时间:2009-09-11 05:56:07

标签: sql

我有很多情况下我的数据库结构类似于:

TABLE事件(EventID INT PrimaryKey,Start DATETIME,Finish DATETIME);和 TABLE EventTask(EventTaskID INT PrimaryKey,EventID INT ForeignKey,TaskStart DATETIME,TaskFinish DATETIME)

事件和EventTasks等之间的1对多关系

当事件表中的日期发生变化时,还需要更改EventTask日期 - 使用提供的日期函数并不困难,但日期操作总是有点棘手。

我想知道用两个INTS替换TaskStart DATETIME和TaskFinish DATETIME是否更好:一个用于Event.Start偏移(不同于Event.Start的分钟)和一个持续时间。

这样日期更新变得更加健壮,因为只有一行需要更新。

(我规定这仅适用于EventTask日期绝对取决于事件日期的情况)

3 个答案:

答案 0 :(得分:2)

是的,这对我来说听起来完全合理。主要的缺点是,为了找到EventTasks的实际时间,你必须执行计算。这将减慢返回时间的任何事情,特别是会损害过滤器中涉及EventTask时间的查询 - 例如“找到在X和Y之间发生的所有任务。”那些以前可以使用索引,但不能再使用索引了。

答案 1 :(得分:1)

如果您使用的是SQL 2008,则可以使用datetimeoffset数据类型。

如果你想“直接”获取数据,没有太多麻烦你可以使用computed columns,但如果结果你可能无法创建索引(或使它们存储结果)是不确定的。

你的结构是这样的:

TABLE [Event] (
    EventID INT PrimaryKey, 
    Start DATETIME, 
    Finish DATETIME)

TABLE [EventTask](
    EventTaskID INT PrimaryKey, 
    EventID INT ForeignKey, 
    TaskStart DATETIMEOFFSET, 
    TaskFinish DATETIMEOFFSET,
    EventTaskStart as [getStartDateByEvent](eventId, TaskStart) <PERSISTED>,
    EventTaskStop as [getStopDateByEvent](eventId, TaskStart) <PERSISTED>,
    )

FUNCTION [getStartDateByEvent](eventId, TaskStart) as DATETIME
BEGIN
    SELECT [EVENT].start + TaskStart from [EVENT] WHERE [EVENT].EVENTID = eventID
END

FUNCTION [getStartDateByEvent](eventId, TaskStop) as DATETIME
BEGIN
    SELECT [EVENT].[finish] + TaskStop from [EVENT] WHERE [EVENT].EVENTID = eventID
END

答案 2 :(得分:0)

Jon Skeet:

  

执行计算。那会的   减慢任何返回的东西   时间,尤其会伤害   涉及EventTask时间的查询   过滤器 - 例如“找到我所有的任务   这发生在时间X和Y之间。“

在我看来,在编写基本数据完整性约束时,您已经有了这个要求,例如:事件的任务日期必须在事件本身的日期内,例如将您的架构扩展为SQL DLL:

CREATE TABLE Event 
(
 EventID INTEGER NOT NULL PRIMARY KEY, 
 event_Start DATETIME NOT NULL, 
 event_Finish DATETIME NOT NULL, 
 CHECK (event_Start < event_Finish), 
 UNIQUE (event_Start, event_Finish, EventID)
)

CREATE TABLE EventTask 
(
 EventTaskID INTEGER NOT NULL PRIMARY KEY, 
 EventID INTEGER NOT NULL, 
 event_Start DATETIME NOT NULL, 
 event_Finish DATETIME NOT NULL, 
 FOREIGN KEY (event_Start, event_Finish, EventID)
    REFERENCES Event (event_Start, event_Finish, EventID)
    ON DELETE CASCADE
    ON UPDATE CASCADE, 
 event_task_START DATETIME NOT NULL, 
 event_task_Finish DATETIME NOT NULL, 
 CHECK (event_task_Start < event_task_Finish), 
 CHECK (event_Start <= event_task_Start), 
 CHECK (event_Finish <= event_task_Finish)
);

如果一个事件的任务是顺序的,那么你还需要编写一个约束来防止重叠周期,这将涉及一个子查询(大多数SQL产品不支持CHECK约束,例如在SQL Server中你会需要诉诸触发器)。如果必须使用时态函数(DATEADD等)重新计算偏移量,那么在高活动环境中性能可能是一个问题,更不用说SQL DLL代码中增加的复杂性了。

由于这些原因,我会根据您的规范建议使用开始和结束数据对建模周期。