4

背景:

我正在设计一个双时态数据库,我们在双时态表之间有 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` 列放入两个数据表中。
  • StartDateEndDate列是双时态的有效时间维度。是EndDate的,有点多余,我们可以只用StartTime.
  • Id两个表的列是新的主键。因为我们对同一个实体有多个行(多个版本,多个有效时间的日期范围),所以实体的ID不能是表的主键。列OrderIdOrderItemId是实体的 ID,但不再是表的主键。除了创建新的主键Id,我们还可以将主键定义为(OrderId, VersionId, StartDate).
  • 如果删除了一个实体,我们只需创建一个新的版本条目,以及在实体表中使用IsDeleted = 1. 表中的所有其他条目(插入和更新)都有IsDeleted = 0.
  • 参考资料栏目FK_OrderId。_ _ 这不再是真正的外键(在数据库约束的意义上),因为不再是主键。但它仍然告诉我们哪些 OrderItems 是某个 Order 的一部分。tblOrderitemOrderIdtblOrderOrderId

这似乎运作良好,我们已经创建了必要的 CRUD 查询并且能够读取和写入双时态数据。

问题:

我需要什么样的约束才能始终如一地工作?

我对如何实现约束不感兴趣(是否将它们实现为数据库约束,如FOREIGN KEYs 或UNIQUE约束,或TRIGGERs,或CHECKs,等等)。我只需要知道我需要什么类型的约束。

我想出了一堆约束,我将把它们作为答案发布。但也许还有更多?

4

1 回答 1

0

(我使用缩写PIVT = 'point in valid time' 。这表示有效时间维度上的某个时间点)

以下是我已经想到的限制:

  • FK_VersionId显然,我们需要对VersionId列进行标准外键约束。
  • 双时唯一性:此外,组合(OrderId, VersionId, StartDate)必须是唯一的(对于 也是相同的tblOrderItem)。
  • 有效时间序列化:我们需要检查每个实体和每个版本的有效时间没有重叠,即列StartDateEndDate不重叠,并且StartDate总是早于EndDate
  • 删除完整性:我们需要确保对于每个实体和每个 PIVT,最多IsDeleted = 1一行带
  • 参照完整性:我们需要检查每个 OrderItem 实体、每个版本和每个 PIVT 的值FK_OrderId是否设置为标识存在于给定 PIVT 处的 Order 实体的值,该实体已插入到早期版本中并且具有未被删除(通过设置IsDeleted = 1)。
于 2013-10-03T16:16:10.633 回答