【发布时间】:2013-10-03 16:16:10
【问题描述】:
背景:
我正在设计一个双时态数据库,我们在双时态表之间有 1:N 关系(我们也有 M:N 关系,但它们只是用一个连接器表和两个 1:N 关系建模,所以我认为它们是 1:N 关系的特例)。
为了说明问题,让我们考虑一个有两个表的简单案例:
|===============| |==================|
| tblOrder | | tblOrderItem |
|============== | |==================|
| - OrderId | | - OrderItemId |
| - OrderNumber | | - FK_OrderId |
|===============| | - Amount |
|==================|
FK_OrderId 是tblOrder 的外键。
为了使这个数据库模型具有双时态,我提出了以下设计:
|===============| |==================| |====================|
| tblOrder | | tblOrderItem | | tblVersions |
|============== | |==================| |====================|
| - Id | | - Id | | - VersionId |
| - OrderId | | - OrderItemId | | - VersionDate |
| - OrderNumber | | - FK_OrderId | |====================|
| - VersionId | | - Amount |
| - IsDeleted | | - VersionId |
| - StartDate | | - IsDeleted |
| - EndDate | | - StartDate |
|===============| | - EndDate |
|==================|
说明:
-
VersionId列是tblVersions表的外键。对于数据库中的每次更改,都会在tblVersions表中创建一个条目。数据的当前状态就是所有版本的总和。这使得重建数据库的先前状态成为可能(通过WHERE VersionDate < ...子句)。这是双时态的交易时间维度。 - 将
tblVersions table could also be avoided if we're just including theVersionDate` 列放入两个数据表中。 -
StartDate和EndDate列是双时态的有效时间 维度。是的,EndDate有点多余,我们可以只用StartTime对表格进行建模。 - 两个表的
Id列是新的主键。因为我们对同一个实体有多个行(多个版本,有效时间中的多个日期范围),实体的ID不能是表的主键。OrderId和OrderItemId列是实体的 ID,但不再是表的主键。除了创建新的主键Id,我们还可以将主键定义为(OrderId, VersionId, StartDate)。 - 如果删除了一个实体,我们只需创建一个新的版本条目,以及在实体表中使用
IsDeleted = 1的条目。表中的所有其他条目(插入和更新)都有IsDeleted = 0。 -
tblOrderitem的列FK_OrderId引用了tblOrder的列OrderId。这不再是真正的外键(在数据库约束的意义上),因为OrderId不再是主键。但它仍然告诉我们哪些 OrderItems 是某个 Order 的一部分。
这似乎运作良好,我们已经创建了必要的 CRUD 查询并且能够读取和写入双时态数据。
问题:
我需要什么样的约束才能使其始终如一地工作?
我对如何实现约束不感兴趣(是否将它们实现为数据库约束,如FOREIGN KEYs 或UNIQUE 约束,或TRIGGERs,或CHECKs,等等)。我只需要知道我需要哪些类型约束。
我想出了一堆约束,我将把它们作为答案发布。但也许还有更多?
【问题讨论】:
标签: constraints temporal temporal-database