2016-05-04 20 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

索引視圖與引起視圖結果更改的數據操作在同一事務中維護。 –