2016-03-23 12 views
0

Ich habe zwei Tabellen (OrderFreshGoods und OrderUtensils) und dann habe ich eine AuditTrail-Tabelle. Die AuditTrail-Tabelle bezieht sich auf die OrderFreshGoods-Tabelle, aber ich möchte sie so ändern, dass sich ein Audit entweder auf einen OrderFreshGoods- oder OrderUtensils-Datensatz beziehen muss. Ich habe viele Lösungen gesehen, bei denen die Audit-Tabelle 2 Fremdschlüssel (OrderIDFresh, OrderIDUtensils und es ist optional, dass 1 von ihnen ausgefüllt werden muss) hat. Beachten Sie, dass ich diese Lösung nicht möchte. Ich möchte, dass die Audit-Tabelle einen Fremdschlüssel (OrderID) hat und sich entweder auf OrderFreshGoods.OrderID oder OrderUtensils.OrderID bezieht.Fremdschlüssel zu 1 von mehreren Tabellen

Auch meine zwei Reihenfolge Tabellen haben keine Felder gemeinsam und werden in einer großen Anzahl von Abfragen rund um das System verwendet, so dass ich nicht eine übergeordnete Tabelle für beide Arten der Bestellung wollen.

Kann jemand helfen? Mein SQL-Skript unten ist, sollten die Kommentare helfen meinen Tests zu erklären ...

--Setup tables 
create table OrderFreshGoods (OrderID int not null primary key, sellBy date, name varchar(20)) 
go 
create table OrderUtensils (OrderID int not null primary key, requiresOver18CheckForKnives bit, colour varchar(20), title varchar(20)) 
go 
create table AuditTrail (AuditId int not null primary key, OrderID int, timeOfEvent date, eventDescription varchar(100)) 
go 

--Base data 
insert into OrderFreshGoods values (7, DATEADD(dd, 3, getdate()), 'Organic milk') 
insert into OrderUtensils values (8, 0, 'Red', 'Garlic crusher') 

--Test data!!!!!!!!!!!!!! 
--This should work 
insert into AuditTrail values (15, 7, getdate(), 'Logging order for Organic Milk from Corkys Coffee shop.') 
--This should work 
insert into AuditTrail values (16, 8, getdate(), 'Logging order for a Red Garlic Crusher from Perrys Pizza Place.') 
--This should not be allowed 
insert into AuditTrail values (17, 9, getdate(), 'Wrongly adding an audit entry before the order, please stop me now!') 
--This should not be allowed 
insert into AuditTrail values (18, null, getdate(), 'Oh dear, bad code has caused the OrderId to be lost, please stop me now!') 
+0

Ich würde hier mit einer Trigger-basierten Lösung gehen. – jarlh

Antwort

1

Was Sie wollen, ist nicht möglich, wie Sie es beschreiben, es geht gegen die sehr Prämisse von relationalen Datenbanken.

Wenn Sie den eigentlichen Fremdschlüssel weglassen, können Sie die AuditTrail.OrderId mit dem, was Sie wollen, füllen.
Aber Sie würden die referenzielle Integritätsprüfung verlieren, so dass Ihre dritte insert into AuditTrail Anweisung nicht fehlschlagen würde. Dies könnte dann durch Anwenden eines On-Insert-Triggers, der eine Referenzprüfung durchführt, behoben werden. Aber es würde immer noch nicht verhindern, dass Befehle gelöscht werden, was dazu führt, dass die Pseudo-Relation wieder schlecht wird.

Eine andere und möglicherweise viel bessere Alternative ist, ein AuditId Feld zu den beiden Auftragstabellen hinzuzufügen und dieses wie erforderlich zu füllen.

+0

Dank Peter, was ich versuche zu berücksichtigen, ist, dass eine Reihe von neuen Tabellen in Zukunft hinzugefügt werden. Deshalb möchte ich die Lösung nicht mit einer gemeinsamen Tabelle, da dies jedes Mal neu bearbeitet werden muss. Dadurch bleibt Ihre Lösung, AuditID zu jeder Auftragstabelle hinzuzufügen. Dies könnte meine Lösung sein, denn wenn Sie darauf hinweisen, verhindert das Verhindern, dass fehlerhafte Daten eingehen, nicht, dass Daten später gelöscht oder aktualisiert werden. Das zu verhindern würde mehr Arbeit erfordern und ich wäre sicherer bei der Verwendung von Fremdschlüsseln. Weil deine Antwort so gut begründet ist, erkenne ich sie als akzeptiert an. – Ewan

0

Wenn Sie immer die richtige Beziehungen nutzen wollen, dann kann ich nächste Lösung sehen:

  1. erstellen noch eine weitere Tabelle xxxx, wie:

    create table xxxx(id int identity(1,1) primary key)

  2. hinzufügen Fremdschlüssel in allen Ihre überprüfbaren Tabellen zu xxxx (id)

  3. neue Datensätze in xxxx erstellen, während Datensätze zu überprüfbaren Tabellen hinzugefügt werden (Auslöser können nützlich sein) (Sie können weitere Informationen in xxxx enthalten)
  4. Tabelle Fremdschlüssel in Audit in den xxxx (id)

Auf diese Weise können in Audit-Tabelle nur Datensätze einfügen kann, um xxxx zeigen - und diese sind immer auf aktuelle Aufträge im Zusammenhang (und verschwinden nicht, wenn eine Bestellung gelöscht wird).