随时间变化的组值的数据库表设计

时间:2017-09-12 20:01:57

标签: sql database database-design

我有以下具有特定名称的组,具体取决于日期:

Group 1:  3/30/2017 to present: status 'on'
Group 2:  3/30/2017 to present: status 'on'
Group 3:  3/30/2017 to present: status 'on'
Group 4:  3/30/2017 to 6/1/2017: status 'off'; 6/2/2017 to present: status: 'on'
Group 5:  3/30/2017 to present: status 'off'
Group 6:  3/30/2017 to 7/10/2017: status 'off'; 7/11/2017 to present: status 'on'

我试图将此信息转换为有效的数据库表,以便我可以指定特定日期的状态更改。

我有一个近乎实时运行的流程,它会检查每个群组的状态,并根据状态执行各种流程。

我想出了以下内容,但我认为这还不够:

Group    Effective Date    Termination Date   Status

Group 1    '2017-03-30'        NULL            On
Group 2    '2017-03-30'        NULL            On
Group 3    '2017-03-30'        NULL            On
Group 4    '2017-03-30'     '2017-06-01'       On
Group 4    '2017-06-02'        NULL            Off
Group 5    '2017-03-30'        NULL            Off
Group 6    '2017-03-30'     '2017-07-10'       Off
Group 6    '2017-07-11'        NULL            On

因此,如果我历史地运行我的日常流程,我希望它能够查阅该表并确定该组的状态。如果我实时运行我的流程,我希望能够查阅表并确定状态。如果我想在特定时间点更改状态,请输入组和状态的终止日期并开始换行。

我无法想象这是一个很好的方法。

寻找见解。

提前致谢。

1 个答案:

答案 0 :(得分:1)

这是一种使用我称之为Version Normal Form(vnf)的方法。它适用于具有平滑,不间断的状态变化链的实体。也就是说,没有间隙(一个状态仅在另一个状态生效时结束)或重叠(任何时候只有一个状态有效)。

使用除状态之外的所有组信息设计Group表。

create table Group(
  ID      int  auto generated primary key,
  ...     ...  -- all other Group data
);

现在创建一个Status表,其中包含一个State字段和一个日期字段 - 状态生效的日期。

create table GroupStatus(
  ID      int  references Group( ID ),
  EffDate date not null default Now(),
  State   char( 1 ) check (State in ('Y', 'N')),
  constraint PK_GroupStatus primary key( ID, EffDate )
);

有关GroupStatus表的两个要点需要考虑:

  • PK定义意味着不能同时定义同一组的两个条目。因此,不可能具有重叠的状态值。
  • 没有“结束”日期。状态在指定的日期和时间生效,并继续有效,直到被另一个状态更改替换。因此,任何集团的状态变化之间都不可能存在差距。

我使用单个字符'Y'(表示开启)和'N'(表示关闭),但您可以按照您想要的任何方式定义状态。这只是为了说明。

EffDate字段可能必须是DateDatetimeTimestamp类型,具体取决于您的特定DBMS。 Now()仅表示使用DBMS中可用的任何方法的“当前日期和时间”。

GroupStatus数据如下所示:

ID    EffDate       State

1    '2017-03-30'   Y
2    '2017-03-30'   Y
3    '2017-03-30'   Y
4    '2017-03-30'   Y
4    '2017-06-02'   N
5    '2017-03-30'   N
6    '2017-03-30'   N
6    '2017-07-11'   Y

对于强制执行的数据完整性级别,设计非常简单。查询会有点复杂。

要查看第1组的当前状态:

select  g.ID as 'Group', s.EffDate as 'Effective Date',
        case s.State when 'Y' then 'On' else 'Off' end as Status
from    Group g
join    GroupStatus s
    on  s.ID = g.ID
    and s.EffDate =(
        select  Max( s1.EffDate )
        from    GroupStatus s1
        where   s1.ID = g.ID
            and s1.EffDate <= Now()
        )
where   g.ID = 1;

要查看所有组的当前状态,请忽略where子句。要查看在特定日期生效的第1组的状态,只需将子查询中的Now()更改为加载了感兴趣的日期和时间的变量。

实际上,将所有组的当前状态查询设置为视图。然后您的日常流程可以简单地查询:

select ID, Status from CurrentGroupStatus;

由于您知道不存在间隙或重叠,因此您知道每个组只有一行。

假设在3月30日插入第6组条目后,您已经知道它将被打开的日期。您可以继续插入具有未来日期(7月11日)的GroupStatus条目,并且“当前”查询和视图将继续显示正确​​的状态(关闭),直到该日期到来,此时ON状态将开始出现。

在视图上创建“而不是”触发器以正确使用基础表,您的应用甚至不必知道数据存储方式的详细信息。

这为您提供了坚实的数据完整性,并且在查看和操作数据方面具有很大的灵活性。

相关问题