Saltar al contenido

Clave foránea para varias tablas

Bienvenido a nuestra página web, en este lugar vas a hallar la resolución a lo que andabas buscando.

Solución:

Tiene algunas opciones, todas varían en “corrección” y facilidad de uso. Como siempre, el diseño correcto depende de sus necesidades.

  • Simplemente podría crear dos columnas en Ticket, OwnedByUserId y OwnedByGroupId, y tener claves externas anulables para cada tabla.

  • Puede crear tablas de referencia M:M que permitan las relaciones ticket:usuario y ticket:grupo. ¿Quizás en el futuro querrá permitir que un solo ticket sea propiedad de varios usuarios o grupos? Este diseño no impone que un boleto deber ser propiedad de una sola entidad.

  • Puede crear un grupo predeterminado para cada usuario y tener boletos que simplemente sean propiedad de un true Grupo o el grupo predeterminado de un usuario.

  • O (mi elección) modele una entidad que actúe como base tanto para Usuarios como para Grupos, y tenga boletos propiedad de esa entidad.

Aquí hay un ejemplo aproximado usando su esquema publicado:

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 primary key,
    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 primary key,
    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 primary key,
    [Owner] int NOT NULL references dbo.Party(PartyId),
    [Subject] varchar(50) NULL
)

La primera opción en la lista de @Nathan Skerl es la que se implementó en un proyecto con el que trabajé una vez, donde se estableció una relación similar entre tres tablas. (Uno de ellos hizo referencia a otros dos, uno a la vez).

Entonces, la tabla de referencia tenía dos extranjeros key columnas, y también tenía una restricción para garantizar que exactamente una tabla (no ambas, ni ninguna) fuera referenciada por una sola fila.

Así es como podría verse cuando se aplica a sus tablas:

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 OwnerGroup IS NULL THEN 0 ELSE 1 END +
      CASE WHEN OwnerUser  IS NULL THEN 0 ELSE 1 END = 1
    )
);

Como puede ver, el Ticket la tabla tiene dos columnas OwnerGroup y OwnerUser, los cuales son extranjeros anulables keys. (Las columnas respectivas en las otras dos tablas se hacen primarias keys en consecuencia.) El CK_Ticket_GroupUser La restricción de verificación asegura que solo uno de los dos key las columnas contienen una referencia (la otra es NULL, por eso ambas tienen que ser anulables).

(El primario key sobre Ticket.ID no es necesario para esta implementación en particular, pero definitivamente no estaría de más tener uno en una tabla como esta).

Otra opción más es tener, en Ticket, una columna que especifica el tipo de entidad propietaria (User o Group), segunda columna con referencia User o Group id y NO usar claves foráneas, sino confiar en un disparador para hacer cumplir la integridad referencial.

Dos ventajas que veo aquí sobre el excelente modelo de Nathan (arriba):

  • Claridad y sencillez más inmediatas.
  • Consultas más sencillas de escribir.

Aquí puedes ver las reseñas y valoraciones de los lectores

Recuerda que te permitimos decir si te fue de ayuda.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *