背景:
我正在设计一个双时态数据库,我们在双时态表之间有 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. - 参考资料栏目
FK_OrderId。_ _ 这不再是真正的外键(在数据库约束的意义上),因为不再是主键。但它仍然告诉我们哪些 OrderItems 是某个 Order 的一部分。tblOrderitemOrderIdtblOrderOrderId
这似乎运作良好,我们已经创建了必要的 CRUD 查询并且能够读取和写入双时态数据。
问题:
我需要什么样的约束才能始终如一地工作?
我对如何实现约束不感兴趣(是否将它们实现为数据库约束,如FOREIGN KEYs 或UNIQUE约束,或TRIGGERs,或CHECKs,等等)。我只需要知道我需要什么类型的约束。
我想出了一堆约束,我将把它们作为答案发布。但也许还有更多?