我的猜测很简单,但有很多可能性......
想象一下,你有一辆汽车,汽车有一个状态(可用,租用,车间,出售......),每个州都有不同的属性:
最后,我们想要记录每辆车的状态。
答案 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')”,您将获得结果中的第三行上面设置:租用。因此,您可以使用相同的查询查看任何特定日期的当前状态或过去状态。