Ich habe 3 relevante Tabellen in meiner Datenbank.
CREATE TABLE dbo.Group
(
ID int NOT NULL,
Name varchar(50) NOT NULL
)
CREATE TABLE dbo.User
(
ID int NOT NULL,
Name varchar(50) NOT NULL
)
CREATE TABLE dbo.Ticket
(
ID int NOT NULL,
Owner int NOT NULL,
Subject varchar(50) NULL
)
Benutzer gehören mehreren Gruppen an. Dies geschieht über eine Beziehung von vielen zu vielen, ist in diesem Fall jedoch irrelevant. Ein Ticket kann entweder einer Gruppe oder einem Benutzer über das Feld dbo.Ticket.Owner gehören.
Wie würde diese Beziehung zwischen einem Ticket und optional einem Benutzer oder einer Gruppe am RICHTIGSTEN beschrieben?
Ich denke, dass ich ein Flag in die Ticket-Tabelle einfügen sollte, das besagt, welcher Typ es besitzt.
sql-server
relational-database
Darthg8r
quelle
quelle
Antworten:
Sie haben einige Optionen, die sich alle in "Korrektheit" und Benutzerfreundlichkeit unterscheiden. Wie immer hängt das richtige Design von Ihren Bedürfnissen ab.
Sie können einfach zwei Spalten in Ticket erstellen, OwnedByUserId und OwnedByGroupId, und jeder Tabelle nullbare Fremdschlüssel zuweisen.
Sie können M: M-Referenztabellen erstellen, die sowohl Ticket: Benutzer- als auch Ticket: Gruppenbeziehungen aktivieren. Vielleicht möchten Sie in Zukunft zulassen, dass ein einzelnes Ticket mehreren Benutzern oder Gruppen gehört? Dieses Design erzwingt nicht, dass ein Ticket nur einer einzelnen Entität gehören darf .
Sie können für jeden Benutzer eine Standardgruppe erstellen und Tickets haben, die entweder einer echten Gruppe oder der Standardgruppe eines Benutzers gehören.
Oder (meine Wahl) eine Entität modellieren, die als Basis für Benutzer und Gruppen fungiert und über Tickets verfügt, die dieser Entität gehören.
Hier ist ein grobes Beispiel mit Ihrem veröffentlichten Schema:
quelle
SELECT t.Subject AS ticketSubject, CASE WHEN u.Name IS NOT NULL THEN u.Name ELSE g.Name END AS ticketOwnerName FROM Ticket t INNER JOIN Party p ON t.Owner=p.PartyId LEFT OUTER JOIN User u ON u.ID=p.PartyId LEFT OUTER JOIN Group g on g.ID=p.PartyID;
Im Ergebnis hätten Sie jeden Betreff und Namen des Tickets.Die erste Option in der Liste von @Nathan Skerl ist die Implementierung in einem Projekt, mit dem ich einmal gearbeitet habe und in dem eine ähnliche Beziehung zwischen drei Tabellen hergestellt wurde. (Einer von ihnen verwies nacheinander auf zwei andere.)
Die Referenzierungstabelle hatte also zwei Fremdschlüsselspalten und eine Einschränkung, um sicherzustellen, dass genau eine Tabelle (nicht beide, nicht keine) von einer einzelnen Zeile referenziert wurde.
So könnte es aussehen, wenn es auf Ihre Tabellen angewendet wird:
Wie Sie sehen können, enthält die
Ticket
Tabelle zwei SpaltenOwnerGroup
undOwnerUser
beide sind nullbare Fremdschlüssel. (Die entsprechenden Spalten in den beiden anderen Tabellen werden entsprechend zu Primärschlüsseln.) DieCK_Ticket_GroupUser
Prüfbedingung stellt sicher, dass nur eine der beiden Fremdschlüsselspalten eine Referenz enthält (die andere ist NULL, daher müssen beide nullwertfähig sein).(Der Primärschlüssel
Ticket.ID
ist für diese bestimmte Implementierung nicht erforderlich, aber es würde definitiv nicht schaden, einen in einer solchen Tabelle zu haben.)quelle
RefID
,RefType
wobeiRefType
es sich um eine feste Kennung der Zieltabelle handelt . Wenn Sie Integrität benötigen, können Sie Überprüfungen in der Trigger- oder App-Ebene durchführen. In diesem Fall ist ein generisches Abrufen möglich. SQL sollte eine solche FK-Definition ermöglichen und unser Leben erleichtern.Eine weitere Option besteht darin, in
Ticket
einer Spalte den Typ (User
oderGroup
) der besitzenden Entität anzugeben , eine zweite Spalte mit ReferenzUser
oderGroup
ID anzugeben und KEINE Fremdschlüssel zu verwenden, sondern sich stattdessen auf einen Trigger zu verlassen, um die referenzielle Integrität zu erzwingen.Zwei Vorteile, die ich hier gegenüber Nathans ausgezeichnetem Modell (oben) sehe :
quelle
Ein anderer Ansatz besteht darin, eine Zuordnungstabelle zu erstellen, die Spalten für jeden potenziellen Ressourcentyp enthält. In Ihrem Beispiel hat jeder der beiden vorhandenen Eigentümertypen eine eigene Tabelle (was bedeutet, dass Sie auf etwas verweisen müssen). Wenn dies immer der Fall sein wird, können Sie so etwas haben:
Mit dieser Lösung würden Sie weiterhin neue Spalten hinzufügen, wenn Sie der Datenbank neue Entitäten hinzufügen, und Sie würden das von @Nathan Skerl angezeigte Fremdschlüsseleinschränkungsmuster löschen und neu erstellen. Diese Lösung ist @Nathan Skerl sehr ähnlich, sieht aber anders aus (je nach Präferenz).
Wenn Sie nicht für jeden neuen Besitzertyp eine neue Tabelle haben, ist es möglicherweise sinnvoll, für jeden potenziellen Eigentümer einen Eigentümertyp anstelle einer Fremdschlüsselspalte anzugeben:
Mit der obigen Methode können Sie so viele Besitzertypen hinzufügen, wie Sie möchten. Owner_ID hätte keine Fremdschlüsseleinschränkung, sondern würde als Referenz auf die anderen Tabellen verwendet. Der Nachteil ist, dass Sie in der Tabelle nachsehen müssen, welche Eigentümertypen es gibt, da dies anhand des Schemas nicht sofort ersichtlich ist. Ich würde dies nur vorschlagen, wenn Sie die Besitzertypen vorher nicht kennen und sie nicht mit anderen Tabellen verknüpft werden. Wenn Sie die Eigentümertypen im Voraus kennen, würde ich eine Lösung wie @Nathan Skerl wählen.
Tut mir leid, wenn ich etwas falsches SQL habe, habe ich das einfach zusammengeschmissen.
quelle
Ich denke, das wäre die allgemeinste Art, das darzustellen, was Sie wollen, anstatt eine Flagge zu verwenden.
quelle