2016-05-04 21 views
1

考虑这个数据库有4个表(星号主键):添加唯一约束的关系,2度远

Products(*ProductId*, SkuText, ...) 
ProductRevisions(ProductId, *RevisionId*, ...) 
Orders(*OrderId*, ...) 
OrderItems(*OrderId*, *ProductRevisionId*, Quantity, ...) 

的想法是,一个产品SKU可以有多个版本(例如2016年的版本的产品与2015版相比)。业务规则是这样的,即ProductOrder只能有一个单独的ProductRevision,例如,订单不能请求同一产品的2014和2016版本,他们只能拥有2014年版 2016版。

按说这不会是一个问题:OrderItems表将有一个ProductId柱,用UNIQUE约束上OrderIdProductId。但是,由于OrderItems的引用ProductRevisionId(所以参考ProductId是间接的),这是一个简单的UNIQUE约束失败和架构将接受以下数据,即使它是为每业务规则无效:

Products 
ProductId, SkuText 
     1, 'Kingston USB Stick' 

ProductRevisions 
ProductId, RevisionId, ... 
     1,   1, '2014 model' 
     1,   2, '2016 model' 

Orders 
OrderId 
     1 

OrderItems 
OrderId, ProductRevisionId, Quantity 
     1,     1,  100 
     1,     2,  50 -- Invalid data! Two revisions of the same Product should not be in the same order. 

我需要的是这样的:

ALTER TABLE OrderItems 
    ADD CONSTRAINT UNIQUE (OrderId, SELECT ProductId FROM ProductRevisions WHERE RevisionId = OrderItems.ProductRevisionId) 

我不想通过增加一个明确的ProductId列进行非规范化我OrderItems表,因为这增加了潜在的故障点,如果给定的父/子关系ProductIdProductRevisionId被改变,那么数据变得无效。

我有什么选择?

回答

1

这实在是更多的评论,但它太长了。

一个选项是创建一个触发器。这使您可以使用所需的任何规则验证数据。但是,触发器繁琐且不必要。

另一种选择基本上就是您所说的:在OrderLines中包括ProductProductRevision。但是,这并不能解决问题。您需要确保产品实际上与修订版本上的产品相匹配。

我在想,最好的选择可能是在ProductRevisionsRevision列。因此,该表将有:

  • ProductRevisionId - 表
  • ProductId
  • RevisionId
  • 唯一约束主键上(ProductId, RevisionId)

外键约束在OrderLines可以再有两列 - (ProductId, RevisionId)。然后,(OrderId, ProductId)上的唯一限制只能确保一个修订。

该方法的缺点是产品只能出现在每个订单的一行中。但是,您不需要触发器。

+0

”这种方法的缺点是产品只能出现在每个订单中只有一行。“ - 这不是一个缺点,这正是我所追求的:) – Dai

0

您可以创建一个索引视图来强制约束。在你的情况下,它会是这样的:

create view [OrderItemProductRevisions] 
with schemabinding 
as 
    select oi.OrderID, pr.ProductID 
    from dbo.OrderItems as oi 
    join dbo.ProductRevisions as pr 
     on oi.ProductRevisionID = pr.ProductRevisionID 
go 
create unique clustered index [CUIX_OrderItemProductRevisions] 
    on [OrderItemProductRevisions] (OrderID, ProductID) 
go 

现在,如果你尝试在同一产品的两个版本添加到同一订单,你应该违反视图上的唯一索引,它会被禁止。 “

+0

索引只有在更新时才会更新接下来查询视图,或者每当表有数据更新时都评估所有视图和视图索引? – Dai

+0

索引视图与引起视图结果更改的数据操作在同一事务中维护。 –