Sie haben zwei Statuswerte, Genehmigt und Abgelehnt. Genehmigt ist weiter unterteilt in zwei Teilstatuswerte, "Geliefert" und "Storniert". Beginnen wir damit, dass wir drei Statuswerte haben, abgelehnt, geliefert und storniert und sehen, wie unser Design funktioniert.
Die WorkOrder-Tabelle wird wie in der Frage gezeigt, daher benötigen wir eine Statustabelle, die den Status dem Arbeitsauftrag zuordnet, alle Daten für alle Statuswerte enthält und einen Hinweis darauf gibt, wo die Daten liegen Der Status kann gefunden werden.
create table Status(
WOID int primary key,
Value char(1) check(Value in ('R', 'D', 'C')),
By int not null, -- who approved, rejected or authorized this status
AsOf date not null, -- and when.
constraint FK_Status_WorkOrder(WOID)
references WordOrder(ID),
constraint FK_By_Employee(By)
references Employee(ID)
);
Zu diesem Zeitpunkt wissen wir dort verwendet, um mehr Tabellen werden Statusdetails (benannt, als eine Vermutung, so etwas wie Rejects, Lieferungen, Brechen) enthalten. Aber wir können kein Feld definieren, das für jede dieser anderen Tabellen ein FK ist, und die Definition von drei solchen Feldern wird sowohl das Design als auch die Aufrechterhaltung der Datenintegrität der laufenden Datenbank erschweren. Zum Glück gibt es einen Weg um ihn herum.
Wir haben die FKs in den drei Detailtabellen, die sich auf die Status-Tabelle beziehen. Aber zuerst müssen wir durch das Hinzufügen einer zusätzlichen Einschränkung der Statustabelle vorbereiten:
create table Status(
...,
constraint UQ_Status_By_Type unique(WOID, Value)
);
Wenn Sie Aufmerksamkeit zahlen sind, können Sie sich fragen, warum wir einen eindeutigen Index für zwei Felder erzeugen würde, von denen einzigartig ganz für sich. Der Grund besteht darin, einen Hook zu definieren, auf den die drei Detailtabellen zugreifen können.
create table Rejects(
WOID int primary key,
Value char(1) check(Value = 'R'),
Reason varchar(10),
constraint FK_Rejects_Status(WOID, Value)
references Status(WOID, Value)
);
Die anderen Detailtabellen sind ähnlich definiert.
Lassen Sie uns untersuchen, was wir bisher haben. Das WOID-Feld der Status-Tabelle stellt sicher, dass es für jeden Arbeitsauftrag nicht mehr als einen Status geben kann und dass die Prüfbeschränkung sicherstellt, dass es entweder Abgelehnt, Geliefert oder Abgebrochen sein muss. Wenn ein WO-Status beispielsweise als Abgelehnt definiert ist, muss in der Status-Tabelle ein Eintrag mit einem Wert von "R" gemacht werden. Daher kann nur ein entsprechender Eintrag in der Abweisungstabelle (der nur einen Wert von "R" enthalten kann) für diese WO gemacht werden. Ein Eintrag in der Tabelle Delivered (der nur einen Statuswert von "D" haben kann) würde vom System abgelehnt.
So wird die Datenintegrität beibehalten. Leider ist die Datenintegrität am Ende des Designs zu oft beschlagnahmt. Ich denke, es sollte das primäre Designprinzip sein.
Verfeinerungen sind natürlich möglich. Beispielsweise könnte das Value-Feld der Statustabelle anstelle einer Prüfbeschränkung selbst ein Fremdschlüssel für eine Nachschlagetabelle sein. Das würde es leicht machen, zu einem späteren Zeitpunkt neue Statuswerte hinzuzufügen.
Angenommen, Sie müssen nicht mehrere Status von Genehmigt, Abgelehnt verfolgen, dann sollten Sie _alle_ dieser Felder in dieselbe Tabelle einfügen. Optional könnten Sie Prüfbedingungen hinzufügen, die sicherstellen, dass Datensätze, die genehmigt sind, RejectedBy und RejectedReason = NULL usw. haben müssen. Die wichtige Frage lautet: Müssen Sie mehrere Zustandsänderungen im Zeitverlauf verfolgen? Der einzige Grund, warum Sie diese in eine andere Tabelle legen, ist, wenn eine bestimmte Arbeitsreihenfolge im Laufe der Zeit viele Änderungen erfahren hat. –