2016-05-04 9 views
1

diese Datenbank mit 4 Tabellen (Primärschlüssel in Sternchen) Erwägen Sie eines Produkts im Vergleich zu seiner Version 2015). Die Geschäftsregeln sind derart, dass ein Order für einen Product nur einen einzigen ProductRevision, z. Eine Bestellung kann nicht sowohl die Versionen 2014 und 2016 des gleichen Produkts anfordern, sie können nur die 2014 oder 2016 Version haben.eine eindeutige Einschränkung für eine Beziehung 2 Grad entfernt

Normalerweise wäre dies kein Problem sein: die OrderItems Tabelle eine ProductId Spalte mit einer UNIQUE Einschränkung für OrderId und ProductId haben würde. Doch weil OrderItems ‚s Referenzen ProductRevisionId (so der Hinweis auf die ProductId indirekt ist) bedeutet dies eine einfache UNIQUE Einschränkung fehlschlägt und das Schema folgende Daten akzeptieren würde, auch wenn es als pro Geschäftsregeln ungültig ist:

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. 

Was ich brauche, ist so etwas wie dieses:

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

ich will nicht meine OrderItems Tabelle denormalize durch Hinzufügen einer expliziten ProductId Spalte, weil das eine potenzielle Fehlerquelle hinzufügt, wenn die Eltern/Kind-Beziehung zwischen einem gegebenen ProductId und ProductRevisionId sollten geändert werden, dann werden die Daten ungültig.

Was sind meine Optionen?

Antwort

1

Dies ist wirklich mehr ein Kommentar, aber es ist zu lang.

Eine Option besteht darin, einen Trigger zu erstellen. Auf diese Weise können Sie die Daten mit den gewünschten Regeln überprüfen. Auslöser sind jedoch umständlich und unnötig.

Eine andere Option ist im Wesentlichen, was Sie sagen: beide Product und ProductRevision in OrderLines. Dies löst das Problem jedoch nicht vollständig. Sie müssen sicherstellen, dass das Produkt tatsächlich mit dem Produkt in der Revision übereinstimmt.

Ich denke, dass die beste Option wäre, eine Revision Spalte in ProductRevisions zu haben. So würde diese Tabelle haben:

  • ProductRevisionId - Primärschlüssel für die Tabelle
  • ProductId
  • RevisionId
  • eindeutige Einschränkung auf (ProductId, RevisionId)

Der Fremdschlüssel in OrderLines kann dann habe zwei Spalten drin - (ProductId, RevisionId). Dann stellt eine eindeutige Beschränkung auf nur eine Revision sicher.

Der Nachteil dieser Methode ist, dass ein Produkt nur in einer Zeile in jeder Reihenfolge erscheinen kann. Sie benötigen jedoch keine Trigger.

+0

"Der Nachteil dieser Methode ist, dass ein Produkt nur in einer Zeile in jeder Reihenfolge erscheinen kann." - das ist kein Nachteil, das ist genau das, was ich habe :) – Dai

0

Sie können eine indizierte Sicht erstellen, um die Abhängigkeit zu erzwingen.

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 

Nun, wenn Sie versuchen, zwei Revisionen des gleichen Produkts auf der gleichen Reihenfolge hinzuzufügen, sollten Sie den eindeutigen Index für die Ansicht verletzen, und es wird nicht zugelassen werden: In Ihrem Fall würde es so etwas wie .

+0

Würde der Index nicht nur aktualisiert werden wenn Die Ansicht wird als nächstes abgefragt, oder werden alle Ansichten und Ansichtsindizes ausgewertet, wenn eine Tabelle Daten aktualisiert hat? – Dai

+0

Die indizierte Sicht wird in der gleichen Transaktion verwaltet wie die Datenmanipulation, die zur Änderung der Ansichtsergebnisse führte. –

Verwandte Themen