存储数据范围 - 有效表示

时间:2012-05-28 15:26:46

标签: sql sql-server database-design relational-database

我需要在时间轴中存储每天的值,即每个数据库用户都应该为每天分配状态,如下所示:

from 1.1.2000 to 28.05.2011 - status 1
from 29.05.2011 to 30.01.2012 - status 3
from 1.2.2012 to infinity - status 4

每天应该只分配一个状态,并且最后状态不会结束(直到给出另一个状态)。我的问题是什么是sql数据库中的有效表示?显而易见的解决方案是为每个更改创建行(在每个范围内分配状态的最后一天),如下所示:

uptodate     status
28.05.2011   status 1
30.01.2012   status 3
01.01.9999   status 4

这有很多问题 - 如果我想添加另一个范围,比如从2012年2月15日开始,我还需要改变最后一行:

uptodate     status
28.05.2011   status 1
30.01.2012   status 3
14.02.2012   status 4
01.01.9999   status 8

并且需要进行大量检查以确保没有重叠和错误,特别是如果有人想要修改列表中间的范围 - 从29.01.2012插入新状态到10.02.2012很难实现(它需要状态3和状态4的数据范围相应地缩小以为新状态腾出空间)。有没有更好的解决方案?


我想到了完整的其他解决方案,比如将每一天的状态存储在单独的行中 - 因此在时间轴中每天都会有行。这样可以轻松更新 - 只需在开始和结束之间输入日期的行的新状态。当然这会产生大量不必要的数据,因此这是一个糟糕的解决方案,但是连贯且易于管理。我想知道中间是否有什么东西,但我猜不是。


更多上下文:我希望版主能够自由地为任何日期分配状态,并在需要时编辑它。但大多数情况下,主持人最后会添加新的状态数据范围。我真的不需要最后的状态。在主持人完成整月编辑后,我需要根据当月每天的状态生成raport。但是,任何时候主持人可能想要在几个月前编辑数据(这将反映在更新的raports上),并且他可以提前一年提供一个状态。

2 个答案:

答案 0 :(得分:1)

您似乎想要将此表用于两件事 - 记录当前状态和状态更改的历史记录。您应该将当前状态分开并将其移至父级(就像注册日期一样)

User
===============
Registered Date
Current Status

Status History
===============
Uptodate 
Status

答案 1 :(得分:0)

您的表格结构应包含状态期间的有效日期和结束日期。这有效地将状态“平铺”为不重叠的组。最后一行应该有一个虚拟结束日期(如上所述)或NULL。如果在结束日期有索引,则使用值而不是NULL非常有用。

使用此结构,要获取任何给定日期的状态,请使用查询:

select *
from t
where <date> between effdate and enddate

要在期末添加新状态,需要进行两项更改:

  1. 使用enddate = 01/01/9999修改表格中的行,以获得昨天的结束日期。
  2. 使用今天的结果和01/01/9999的结束日期插入一个新行
  3. 我会将它包装在存储过程中。

    要更改过去某个日期的状态,需要将其中一个历史记录拆分为两个。多个日期可能需要更改多个记录。

    如果您有日期范围,则可以使用查询获取与给定时间段重叠的所有切片:

    select *
    from t
    where <periodstart> <= enddate and <periodend> >= effdate