188 votes

Clé étrangère à plusieurs tables

J'ai 3 tableaux pertinents 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. Ceci est fait par l'intermédiaire d'une relation plusieurs-à-plusieurs, mais rien dans ce cas. Un billet peut être détenue par un groupe ou un utilisateur, via la dbo.Billet d'.Le propriétaire du champ.

Ce serait la PLUS juste façon de décrire cette relation entre un billet et éventuellement d'un utilisateur ou d'un groupe?

Je pense que je devrais ajouter un drapeau dans le billet table qui dit que ce type est le propriétaire.

195voto

Nathan Skerl Points 4441

Vous avez un peu d'options, toutes les variables dans la "correction" et la facilité d'utilisation. Comme toujours, la bonne conception dépend de vos besoins.

  • Vous pourriez simple de créer deux colonnes, dans le Billet, OwnedByUserId et OwnedByGroupId, et ont nullable Fks à chaque table.

  • Vous pouvez créer M:M tables de référence permettant à la fois de billet:l'utilisateur et le billet:relations de groupe. Peut-être dans l'avenir, vous voulez permettre à un seul billet à être détenue par plusieurs utilisateurs ou groupes? Cette conception ne fait pas valoir que le billet doit être détenue par une seule entité.

  • Vous pouvez créer un groupe par défaut pour chaque utilisateur et des tickets simplement possédé par un vrai Groupe ou d'un Utilisateur à un Groupe par défaut.

  • Ou (mon choix) modèle d'une entité qui agit comme une base pour les Utilisateurs et les Groupes, et ont des billets propriétaire par cette entité.

Heres un exemple grossier à l'aide de votre posté schéma:

create table dbo.PartyType
(   
    PartyTypeId tinyint primary key,
    PartyTypeName varchar(10)
)

insert into dbo.PartyType
    values(1, 'User'), (2, 'Group');


create table dbo.Party
(
    PartyId int identity(1,1) primary key,
    PartyTypeid tinyint references dbo.PartyType(PartyTypeId),
    unique (PartyId, PartyTypeId)
)

CREATE TABLE dbo.[Group]
(
    ID int NOT NULL,
    Name varchar(50) NOT NULL,
    PartyTypeId as cast(2 as tinyint) persisted,
    foreign key (ID, PartyTypeId) references Party(PartyId, PartyTypeID)
)  

CREATE TABLE dbo.[User]
(
    ID int NOT NULL,
    Name varchar(50) NOT NULL,
    PartyTypeId as cast(1 as tinyint) persisted,
    foreign key (ID, PartyTypeId) references Party(PartyID, PartyTypeID)
)

CREATE TABLE dbo.Ticket
(
    ID int NOT NULL,
    [Owner] int NOT NULL references dbo.Party(PartyId),
    [Subject] varchar(50) NULL
)

42voto

Andriy M Points 40395

La première option dans @Nathan Skerlla liste est ce qui a été mis en œuvre dans un projet que j'ai déjà travaillé avec, où une relation similaire a été établi entre les trois tableaux. (L'un d'eux mention de deux autres, l'un à la fois).

Ainsi, la table de référence avait deux colonnes de clé étrangère, et aussi elle a une contrainte de garantir qu'une seule table (pas les deux, pas non plus) a été référencée par une seule ligne.

Voici à quoi ça pourrait ressembler quand il est appliqué à vos tables:

CREATE TABLE dbo.[Group]
(
    ID int NOT NULL CONSTRAINT PK_Group PRIMARY KEY,
    Name varchar(50) NOT NULL
);

CREATE TABLE dbo.[User]
(
    ID int NOT NULL CONSTRAINT PK_User PRIMARY KEY,
    Name varchar(50) NOT NULL
);

CREATE TABLE dbo.Ticket
(
    ID int NOT NULL CONSTRAINT PK_Ticket PRIMARY KEY,
    OwnerGroup int NULL
      CONSTRAINT FK_Ticket_Group FOREIGN KEY REFERENCES dbo.[Group] (ID),
    OwnerUser int NULL
      CONSTRAINT FK_Ticket_User  FOREIGN KEY REFERENCES dbo.[User]  (ID),
    Subject varchar(50) NULL,
    CONSTRAINT CK_Ticket_GroupUser CHECK (
      CASE WHEN [Group] IS NULL THEN 0 ELSE 1 END +
      CASE WHEN [User]  IS NULL THEN 0 ELSE 1 END = 1
    )
);

Comme vous pouvez le voir, l' Ticket tableau a deux colonnes, OwnerGroup et OwnerUser, qui sont tous deux nullable clés étrangères. (Les colonnes respectives dans les deux autres tableaux sont réalisés à des clés primaires en conséquence.) L' CK_Ticket_GroupUser la contrainte de vérification s'assure que seule l'une des deux colonnes de clé étrangère contient une référence (l'autre étant NULLE, c'est pourquoi les deux doivent être nullable).

(La clé primaire sur Ticket.ID n'est pas nécessaire pour cette mise en oeuvre particulière, mais il a certainement ne serait pas mal d'en avoir un dans un tableau comme celui-ci.)

-9voto

Francisco Soto Points 5043
 CREATE TABLE dbo.OwnerType
(
    ID int NOT NULL,
    Name varchar(50) NULL
)

insert into OwnerType (Name) values ('User');
insert into OwnerType (Name) values ('Group');
 

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.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X