背景:
我正在设计一个双时态数据库,我们在双时态表之间有 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 the
VersionDate` 列放入两个数据表中。 StartDate
和EndDate
列是双时态的有效时间维度。是EndDate
的,有点多余,我们可以只用StartTime
.- 这
Id
两个表的列是新的主键。因为我们对同一个实体有多个行(多个版本,多个有效时间的日期范围),所以实体的ID不能是表的主键。列OrderId
和OrderItemId
是实体的 ID,但不再是表的主键。除了创建新的主键Id
,我们还可以将主键定义为(OrderId, VersionId, StartDate)
. - 如果删除了一个实体,我们只需创建一个新的版本条目,以及在实体表中使用
IsDeleted = 1
. 表中的所有其他条目(插入和更新)都有IsDeleted = 0
. - 参考资料栏目
FK_OrderId
。_ _ 这不再是真正的外键(在数据库约束的意义上),因为不再是主键。但它仍然告诉我们哪些 OrderItems 是某个 Order 的一部分。tblOrderitem
OrderId
tblOrder
OrderId
这似乎运作良好,我们已经创建了必要的 CRUD 查询并且能够读取和写入双时态数据。
问题:
我需要什么样的约束才能始终如一地工作?
我对如何实现约束不感兴趣(是否将它们实现为数据库约束,如FOREIGN KEY
s 或UNIQUE
约束,或TRIGGER
s,或CHECK
s,等等)。我只需要知道我需要什么类型的约束。
我想出了一堆约束,我将把它们作为答案发布。但也许还有更多?