Tengo 3 tablas relevantes en mi base de datos.
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
)
Los usuarios pertenecen a múltiples grupos. Esto se hace a través de una relación de muchos a muchos, pero irrelevante en este caso. Un boleto puede ser propiedad de un grupo o un usuario, a través del campo dbo.Ticket.Owner.
¿Cuál sería la forma MÁS CORRECTA de describir esta relación entre un ticket y, opcionalmente, un usuario o un grupo?
Estoy pensando que debería agregar una bandera en la tabla de tickets que diga qué tipo es el propietario.
sql-server
relational-database
Darthg8r
fuente
fuente
Respuestas:
Tiene algunas opciones, todas variadas en "corrección" y facilidad de uso. Como siempre, el diseño correcto depende de sus necesidades.
Simplemente puede crear dos columnas en Ticket, OwnedByUserId y OwnedByGroupId, y tener claves foráneas anulables para cada tabla.
Puede crear tablas de referencia M: M que habiliten las relaciones ticket: usuario y ticket: grupo. ¿Quizás en el futuro desee permitir que un solo boleto sea propiedad de múltiples usuarios o grupos? Este diseño no exige que un boleto sea propiedad de una sola entidad solamente.
Puede crear un grupo predeterminado para cada usuario y tener tickets simplemente poseídos por un Grupo verdadero o un Grupo predeterminado del Usuario.
O (mi elección) modelar una entidad que actúa como base tanto para usuarios como para grupos, y tener tickets propiedad de esa entidad.
Aquí hay un ejemplo aproximado usando su esquema publicado:
fuente
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;
En el resultado, tendría cada asunto de boleto y nombre de propietario.La primera opción en la lista de @Nathan Skerl es lo 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 columnas de clave externa, y también tenía una restricción para garantizar que una sola fila hiciera referencia a exactamente una tabla (no ambas, ni ninguna).
Así es como podría verse cuando se aplica a sus tablas:
Como puede ver, la
Ticket
tabla tiene dos columnasOwnerGroup
yOwnerUser
ambas son claves foráneas que pueden contener nulos. (Las columnas respectivas en las otras dos tablas se convierten en claves primarias en consecuencia.) LaCK_Ticket_GroupUser
restricción de verificación asegura que solo una de las dos columnas de clave externa contenga una referencia (la otra es NULL, por eso ambas deben ser anulables).(La clave principal
Ticket.ID
no es necesaria para esta implementación en particular, pero definitivamente no estaría de más tener una en una tabla como esta).fuente
RefID
,RefType
dondeRefType
hay un identificador fijo de la tabla de destino. Si necesita integridad, puede hacer verificaciones en el disparador o la capa de la aplicación. La recuperación genérica es posible en este caso. SQL debería permitir una definición de FK como esta, facilitando nuestras vidas.Otra opción es tener, en
Ticket
, una columna que especifique el tipo de entidad propietaria (User
oGroup
), la segunda columna con referenciaUser
oGroup
id y NO usar claves externas, sino confiar en un activador para hacer cumplir la integridad referencial.Dos ventajas que veo aquí sobre el excelente modelo de Nathan (arriba):
fuente
Otro enfoque es crear una tabla de asociación que contenga columnas para cada tipo de recurso potencial. En su ejemplo, cada uno de los dos tipos de propietarios existentes tiene su propia tabla (lo que significa que tiene algo a lo que hacer referencia). Si este siempre será el caso, puede tener algo como esto:
Con esta solución, continuaría agregando nuevas columnas a medida que agrega nuevas entidades a la base de datos y eliminaría y volvería a crear el patrón de restricción de clave externa que muestra @Nathan Skerl. Esta solución es muy similar a @Nathan Skerl, pero se ve diferente (hasta la preferencia).
Si no va a tener una nueva Tabla para cada nuevo tipo de Propietario, entonces sería bueno incluir un tipo de propietario en lugar de una columna de clave externa para cada Propietario potencial:
Con el método anterior, puede agregar tantos tipos de propietarios como desee. Owner_ID no tendría una restricción de clave externa, pero se utilizaría como referencia para las otras tablas. La desventaja es que tendrías que mirar la tabla para ver cuáles son los tipos de propietarios, ya que no es inmediatamente obvio según el esquema. Solo sugeriría esto si no conoce los tipos de propietario de antemano y no se vincularán a otras tablas. Si conoce de antemano los tipos de propietarios, elegiría una solución como @Nathan Skerl.
Lo siento si me equivoqué con un poco de SQL, solo hice esto.
fuente
Creo que esa sería la forma más general de representar lo que quieres en lugar de usar una bandera.
fuente