J'ai 3 tables pertinentes dans ma base de données.
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
)
Les utilisateurs appartiennent à plusieurs groupes. Cela se fait via une relation plusieurs à plusieurs, mais sans importance dans ce cas. Un ticket peut appartenir à un groupe ou à un utilisateur, via le champ dbo.Ticket.Owner.
Quel serait le PLUS CORRECT façon de décrire cette relation entre un ticket et éventuellement un utilisateur ou un groupe?
Je pense que je devrais ajouter un drapeau dans la table des tickets qui indique quel type le possède.
sql-server
relational-database
Darthg8r
la source
la source
Réponses:
Vous avez quelques options, toutes variant en "exactitude" et en facilité d'utilisation. Comme toujours, la bonne conception dépend de vos besoins.
Vous pouvez simplement créer deux colonnes dans Ticket, OwnedByUserId et OwnedByGroupId, et avoir des clés étrangères nullables pour chaque table.
Vous pouvez créer des tables de référence M: M permettant à la fois les relations ticket: utilisateur et ticket: groupe. Peut-être voudrez-vous à l'avenir autoriser un seul ticket à appartenir à plusieurs utilisateurs ou groupes? Cette conception n'impose pas qu'un ticket doit appartenir à une seule entité uniquement.
Vous pouvez créer un groupe par défaut pour chaque utilisateur et avoir des tickets appartenant simplement à un vrai groupe ou au groupe par défaut d'un utilisateur.
Ou (mon choix) modélisez une entité qui sert de base à la fois aux utilisateurs et aux groupes, et dont les billets sont la propriété de cette entité.
Voici un exemple approximatif utilisant votre schéma publié:
la source
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;
Dans le résultat, vous auriez chaque sujet de ticket et le nom du propriétaire.La première option dans la liste de @Nathan Skerl est ce qui a été implémenté dans un projet avec lequel j'ai travaillé une fois, où une relation similaire a été établie entre trois tables. (L'un d'eux en a fait référence à deux autres, un à la fois.)
Ainsi, la table de référence avait deux colonnes de clé étrangère, et elle avait également une contrainte pour garantir qu'exactement une table (ni les deux, ni aucune) était référencée par une seule ligne.
Voici à quoi cela pourrait ressembler lorsqu'il est appliqué à vos tableaux:
Comme vous pouvez le voir, la
Ticket
table comporte deux colonnesOwnerGroup
etOwnerUser
, qui sont toutes deux des clés étrangères Nullable. (Les colonnes respectives des deux autres tables deviennent des clés primaires en conséquence.) LaCK_Ticket_GroupUser
contrainte de vérification garantit que seule l'une des deux colonnes de clé étrangère contient une référence (l'autre étant NULL, c'est pourquoi les deux doivent être NULL).(La clé primaire sur
Ticket.ID
n'est pas nécessaire pour cette implémentation particulière, mais cela ne ferait certainement pas de mal d'en avoir une dans une table comme celle-ci.)la source
RefID
,RefType
oùRefType
est un identifiant fixe de la table cible. Si vous avez besoin d'intégrité, vous pouvez effectuer des vérifications dans le déclencheur ou la couche d'application. La récupération générique est possible dans ce cas. SQL devrait permettre une définition FK comme celle-ci, ce qui nous facilite la vie.Une autre option encore consiste à avoir, dans
Ticket
, une colonne spécifiant le type d'entité propriétaire (User
ouGroup
), une deuxième colonne avec référencéUser
ouGroup
id et de NE PAS utiliser de clés étrangères, mais plutôt de s'appuyer sur un déclencheur pour appliquer l'intégrité référentielle.Deux avantages que je vois ici par rapport à l' excellent modèle de Nathan (ci-dessus):
la source
Une autre approche consiste à créer une table d'association contenant des colonnes pour chaque type de ressource potentiel. Dans votre exemple, chacun des deux types de propriétaires existants a sa propre table (ce qui signifie que vous avez quelque chose à référencer). Si tel est toujours le cas, vous pouvez avoir quelque chose comme ceci:
Avec cette solution, vous continueriez à ajouter de nouvelles colonnes à mesure que vous ajoutez de nouvelles entités à la base de données et vous supprimeriez et recréeriez le modèle de contrainte de clé étrangère affiché par @Nathan Skerl. Cette solution est très similaire à @Nathan Skerl mais semble différente (selon vos préférences).
Si vous n'allez pas avoir une nouvelle table pour chaque nouveau type de propriétaire, il serait peut-être bon d'inclure un owner_type au lieu d'une colonne de clé étrangère pour chaque propriétaire potentiel:
Avec la méthode ci-dessus, vous pouvez ajouter autant de types de propriétaires que vous le souhaitez. Owner_ID n'aurait pas de contrainte de clé étrangère mais serait utilisé comme référence aux autres tables. L'inconvénient est que vous devriez regarder le tableau pour voir quels types de propriétaires il y a car ce n'est pas immédiatement évident en fonction du schéma. Je ne suggérerais cela que si vous ne connaissez pas les types de propriétaires à l'avance et qu'ils ne seront pas liés à d'autres tables. Si vous connaissez à l'avance les types de propriétaires, j'irais avec une solution comme @Nathan Skerl.
Désolé si je me trompe de SQL, je viens de jeter ceci ensemble.
la source
Je pense que ce serait la manière la plus générale de représenter ce que vous voulez au lieu d'utiliser un drapeau.
la source