为多个统计信息创建BD结构

时间:2016-10-29 09:07:05

标签: database database-design structure states

我的猜测很简单,但有很多可能性......

想象一下,你有一辆汽车,汽车有一个状态(可用,租用,车间,出售......),每个州都有不同的属性:

  • 可用:我们希望保持员工已建立状态和日期。
  • 租用:员工,客户(公司或个人),开始日期,结束日期和价格
  • 在车间:研讨会,约会。
  • 已售出:客户(公司或个人),员工,日期,价格。

最后,我们想要记录每辆车的状态。

1 个答案:

答案 0 :(得分:0)

易。这是一个具有多值属性(状态)的实体(汽车)。让我们使用 status state 这个词有更明显的含义。但是,实体具有仅根据状态应用的其他关联属性,因此可以将 status 属性视为实体。这种汽车的状态表示为与状态“实体”的关系。您记录状态的其他要求也很容易。但要注意,这并不简单。

create table Cars(
  ID   int    auto_generated primary key,
  ...  ...    -- other attributes
);

状态具有基类,子类格式

create table Status(
  ID   char( 1 ) not null primary key, -- 'A', 'R', 'W', 'S'
  Label varchar  not null - 'Available', 'Rented', 'In Workshop', 'Sold'
  constraint UQ_StatusLabel unique( ID, Label )
);

现在包含汽车实际状态信息的表格。

create table AStatus(
  A_ID char( 1 )    check( A_ID = 'A' ),
  EstablishedBy int not null references Employees( ID ),
);

create table RStatus(
  R_ID char( 1 )    check( R_ID = 'R' ),
  RentedBy   int    not null references Employees( ID ),
  RentedTo   int    not null references Clients( ID ),
  Price      currency not null
);

create table WStatus(
  W_ID char( 1 )    check( W_ID = 'W' ),
  WS_ID  int not null references Workshops( ID )
);

create table SStatus(
  S_ID char( 1 )    check( S_ID = 'S' ),
  SoldBy     int    not null references Employees( ID ),
  SoldTo     int    not null references Clients( ID ),
  Price      currency not null
);

最后,将这些全部联系起来的交叉表。

create table CarStatus(
  CarID    int  not null references Cars( ID ),
  EffDate  date      not null default Now(),
  StatusID char( 1 ) not null references Status( ID ),
  constraint PK_CarStatus primary key( CarID, EffDate )
);

让我们跟随一辆车,因为它进入车间,变得可用,出租,退回(再次可用)然后出售。所有这些变化都在连续几个月的第一天发生(很方便)。

CarStatus    xStatus
1 1/1/16 W   W  17      -- Jan 1, Car #1 goes to workshop 17
1 2/1/16 A   A  2       -- Feb 1, Employee #2 makes if available
1 3/1/16 R   R  2 12 24 -- Mar 1, Employee #2 rents to client #12 for $24
1 4/1/16 A   A  3       -- Apr 1, Employee #3 returns car to Available
1 5/1/16 S   S  3 13 20000 -- May 1, Employee #3 sells car to client #13 for $20000

请注意,表格行不会互相替换。因此CarStatus表包含如图所示的五行,AStatus包含两行,每个其他xStatus表各包含一行。

阅读汽车#1的历史记录:

select  c.id CarID, s.Label Status, cs.EffDate "Effective Date"
from    CarStatus cs
join    Cars      c
    on  c.ID = cs.CarID
join    Status    s
    on  s.ID = cs.StatusID
where   cs.CarID = 1
order by cs.EffDate;

CarID   Status       Effective Date
    1   In Workshop  1/1/16
    1   Available    2/1/16
    1   Rented       3/1/16
    1   Available    4/1/16
    1   Sold         5/1/16

请注意,租赁只有一个日期。返回日期是汽车下一次可用的日期。如果返回和再次可用之间有一段时间,例如清洁,则添加另一个状态。像,哦,清洁。 (或者你可以在RStatus表中添加一个“ReturnDate”字段,但是这会打开你的异常数据的可能性,所以你必须要格外警惕。)

显示汽车的当前状态更为复杂。但我正在使用Version Normal Form(以我的名义搜索它以获取更多详细信息),这是我用来维护数据更改历史的标准模式。因此查询也适合快速学习的标准模式。

select  c.id CarID, s.Label Status, cs.EffDate "Effective Date"
from    CarStatus cs
join    CarStatus cs2
    on  cs2.CarID = cs.CarID
    and cs2.EffDate =(
        select  Max( cs3.EffDate )
        from    CarStatus cs3
        where   cs3.EffDate <= Now() )
join    Cars      c
    on  c.ID = cs.CarID
join    Status    s
    on  s.ID = cs.StatusID
where   cs.CarID = 1
order by cs.EffDate;

这将显示上面结果集的最后一行,因为这是输入的最后一个状态。您可以删除WHERE和ORDER BY子句,并使用此查询创建一个显示所有汽车当前状态的视图。

这是很酷的部分。假设您想要查看截至3月15日的汽车状态。只需将上面查询中的“Now()”更改为“to_date('3/15/16')”,您将获得结果中的第三行上面设置:租用。因此,您可以使用相同的查询查看任何特定日期的当前状态或过去状态。