Sí, la identificación de asociaciones o relaciones de muchos a muchos (M: N para abreviar) es una situación que un profesional de bases de datos enfrenta con bastante frecuencia al diseñar un esquema conceptual. Las asociaciones de dichas proporciones de cardinalidad se producen en entornos empresariales de naturaleza muy diferente, y cuando se representan adecuadamente en el nivel lógico por medio de, por ejemplo, una disposición SQL-DDL, no introducen redundancias perjudiciales.
De esta manera, el objetivo de un ejercicio de modelado de bases de datos debe ser reflejar las características relevantes del contexto de negocios de interés con alta precisión ; por lo tanto, si identifica correctamente que existen numerosas asociaciones M: N, debe expresarlas en (a) el esquema conceptual y también en (b) las respectivas declaraciones de nivel lógico, sin importar cuántas conexiones de eso, o cualquier otro tipo de tasas de cardinalidad deben ser abordadas.
Reglas del negocio
Ha proporcionado una pregunta bien contextualizada y también ha aclarado que la base de datos en la que está trabajando es puramente hipotética, lo cual es un punto importante ya que considero que un escenario de negocios del "mundo real" como el que se está considerando sería mucho más extenso y, por lo tanto, implicaría requisitos informativos más complejos.
Decidí (1) hacer algunas modificaciones y expansiones a las reglas de negocios que usted ha provisto para (2) producir un esquema conceptual más descriptivo, aunque todavía bastante hipotético. Estas son algunas de las formulaciones que preparé:
- Una Parte 1 es una Persona o una Organización
- Una fiesta se clasifica exactamente por un PartyType
- Un PartyType clasifica cero-uno-o-muchos partidos
- Una organización desarrolla cero uno o muchos productos
- Un producto es un sistema o un juego
- Un producto se clasifica exactamente por un tipo de producto
- Un sistema está catalogado exactamente por un tipo de sistema
- Un juego se puede jugar a través de sistemas uno a muchos
- Un sistema se utiliza para reproducir uno-a-muchos juegos
- Un juego está clasificado por cero-uno o muchos géneros
- Un género clasifica los juegos de cero uno o muchos
- Un producto origina trabajos de uno a muchos
- Un trabajo se cumple por cero-una o muchas personas , que desempeñan el papel de colaboradores
- Una persona es un colaborador en trabajos de cero uno o muchos
1 Parte es un término utilizado en contextos legales cuando se refiere a un individuo o un grupo de individuos que componen una sola entidad, por lo que esta denominación es adecuada para representar a personas y organizaciones .
Diagrama IDEF1X
Posteriormente, creé el diagrama IDEF1X 2 que se muestra en la Figura 1 (asegúrese de hacer clic en el enlace para verlo en una resolución más alta), consolidando en un solo dispositivo gráfico las reglas comerciales presentadas anteriormente (junto con algunas otras que parecen relevantes):
2 La definición de integración para el modelado de información ( IDEF1X ) es una técnica de modelado de datos altamente recomendable que fue establecida como estándar en diciembre de 1993 por el Instituto Nacional de Estándares y Tecnología de los Estados Unidos (NIST). Se basa en (a) el material teórico inicial escrito por el único autor del modelo relacional, es decir, el Dr. EF Codd; en (b) la vista de datos entidad-relación , desarrollada por el Dr. PP Chen ; y también en (c) la Técnica de diseño de base de datos lógica, creada por Robert G. Brown.
Como puede ver, he representado solo tres asociaciones M: N a través de los tipos de entidad asociativa correspondientes , es decir:
- Colaborador
- SystemGame
- GameGenre
Entre otros aspectos, hay dos estructuras distintas de supertipo-subtipo , donde:
Persona y Organización son subtipos de entidad mutuamente excluyentes de Parte , su supertipo de entidad
El producto es el supertipo de Sistema y Juego , que a su vez son subtipos mutuamente excluyentes
En caso de que no esté familiarizado con las asociaciones de supertipo-subtipo, puede encontrar ayuda, por ejemplo, mis respuestas a las preguntas tituladas:
Diseño ilustrativo de SQL-DDL lógico
Sucesivamente, debemos asegurarnos de que, a nivel lógico:
- Cada tipo de entidad está representado por una tabla base individual
- Cada propiedad individual del tipo de entidad aplicable se denota por una columna particular
- Se fija un tipo de datos exacto para cada columna para garantizar que todos los valores que contiene pertenecen a un conjunto particular y bien definido, ya sea INT, DATETIME, CHAR, etc. (por supuesto, cuando se usa, por ejemplo, Firebird o PostgreSQL , es posible que desee emplear los DOMINIOS más potentes)
- Se configuran múltiples restricciones (declarativamente) para garantizar que las aserciones en forma de filas retenidas en todas las tablas cumplan con las reglas de negocio determinadas a nivel conceptual
Así que declaró la siguiente disposición DDL basada en el diagrama IDEF1X mostrado anteriormente:
CREATE TABLE PartyType ( -- Stands for an independent entity type.
PartyTypeCode CHAR(1) NOT NULL, -- To retain 'P' or 'O'.
Name CHAR(30) NOT NULL, -- To keep 'Person' or 'Organization'.
--
CONSTRAINT PartyType_PK PRIMARY KEY (PartyTypeCode)
);
CREATE TABLE Party ( -- Represents an entity supertype.
PartyId INT NOT NULL,
PartyTypeCode CHAR(1) NOT NULL, -- To hold the value that indicates the type of the row denoting the complementary subtype occurrence: either 'P' for 'Person' or 'O' for 'Organization'.
CreatedDateTime TIMESTAMP NOT NULL,
--
CONSTRAINT Party_PK PRIMARY KEY (PartyId),
CONSTRAINT PartyToPartyType_FK FOREIGN KEY (PartyTypeCode)
REFERENCES PartyType (PartyTypeCode)
);
CREATE TABLE Person ( -- Denotes an entity subtype.
PersonId INT NOT NULL, -- To be constrained as (a) the PRIMARY KEY and (b) a FOREIGN KEY.
FirstName CHAR(30) NOT NULL,
LastName CHAR(30) NOT NULL,
GenderCode CHAR(3) NOT NULL,
BirthDate DATE NOT NULL,
--
CONSTRAINT Person_PK PRIMARY KEY (PersonId),
CONSTRAINT Person_AK UNIQUE (FirstName, LastName, GenderCode, BirthDate), -- Composite ALTERNATE KEY.
CONSTRAINT PersonToParty_FK FOREIGN KEY (PersonId)
REFERENCES Party (PartyId)
);
CREATE TABLE Organization ( -- Stands for an entity subtype.
OrganizationId INT NOT NULL, -- To be constrained as (a) the PRIMARY KEY and (b) a FOREIGN KEY.
Name CHAR(30) NOT NULL,
FoundingDate DATE NOT NULL,
--
CONSTRAINT Organization_PK PRIMARY KEY (OrganizationId),
CONSTRAINT Organization_AK UNIQUE (Name), -- Single-column ALTERNATE KEY.
CONSTRAINT OrganizationToParty_FK FOREIGN KEY (OrganizationId)
REFERENCES Party (PartyId)
);
CREATE TABLE ProductType ( -- Represents an independent entity type.
ProductTypeCode CHAR(1) NOT NULL, -- To enclose the values 'S' and 'G' in the corresponding rows.
Name CHAR(30) NOT NULL, -- To comprise the values 'System' and 'Person' in the respective rows.
--
CONSTRAINT ProductType_PK PRIMARY KEY (ProductTypeCode)
);
CREATE TABLE Product ( -- Denotes an entity supertype.
OrganizationId INT NOT NULL,
ProductNumber INT NOT NULL,
ProductTypeCode CHAR(1) NOT NULL, -- To keep the value that indicates the type of the row denoting the complementary subtype occurrence: either 'S' for 'System' or 'G' for 'Game'.
CreatedDateTime DATETIME NOT NULL,
--
CONSTRAINT Product_PK PRIMARY KEY (OrganizationId, ProductNumber), -- Composite PRIMARY KEY.
CONSTRAINT ProductToOrganization_FK FOREIGN KEY (OrganizationId)
REFERENCES Organization (OrganizationId),
CONSTRAINT ProductToProductType_FK FOREIGN KEY (ProductTypeCode)
REFERENCES ProductType (ProductTypeCode)
);
CREATE TABLE SystemType ( -- Stands for an independent entity type.
SystemTypeCode CHAR(1) NOT NULL,
Name CHAR(30) NOT NULL,
--
CONSTRAINT SystemType_PK PRIMARY KEY (SystemTypeCode)
);
CREATE TABLE MySystem ( -- Represents a dependent entity type.
OrganizationId INT NOT NULL, -- To be constrained as (a) the PRIMARY KEY and (b) a FOREIGN KEY.
SystemNumber INT NOT NULL,
SystemTypeCode CHAR(1) NOT NULL,
ParticularColumn CHAR(30) NOT NULL,
--
CONSTRAINT System_PK PRIMARY KEY (OrganizationId, SystemNumber),
CONSTRAINT SystemToProduct_FK FOREIGN KEY (OrganizationId, SystemNumber)
REFERENCES Product (OrganizationId, ProductNumber),
CONSTRAINT SystemToSystemType_FK FOREIGN KEY (SystemTypeCode)
REFERENCES SystemType (SystemTypeCode)
);
CREATE TABLE Game ( -- Denotes an entity subtype.
OrganizationId INT NOT NULL, -- To be constrained as (a) the PRIMARY KEY and (b) a FOREIGN KEY.
GameNumber INT NOT NULL,
SpecificColumn CHAR(30) NOT NULL,
--
CONSTRAINT Game_PK PRIMARY KEY (OrganizationId, GameNumber),
CONSTRAINT GameToProduct_FK FOREIGN KEY (OrganizationId, GameNumber)
REFERENCES Product (OrganizationId, ProductNumber)
);
CREATE TABLE Genre ( -- Stands for an independent entity type.
GenreNumber INT NOT NULL,
Name CHAR(30) NOT NULL,
Description CHAR(90) NOT NULL,
--
CONSTRAINT Genre_PK PRIMARY KEY (GenreNumber),
CONSTRAINT Genre_AK1 UNIQUE (Name),
CONSTRAINT Genre_AK2 UNIQUE (Description)
);
CREATE TABLE SystemGame ( -- Represents an associative entity type or M:N association.
SystemOrganizationId INT NOT NULL,
SystemNumber INT NOT NULL,
GameOrganizationId INT NOT NULL,
GameNumber INT NOT NULL,
CreatedDateTime DATETIME NOT NULL,
--
CONSTRAINT SystemGame_PK PRIMARY KEY (SystemOrganizationId, SystemNumber, GameOrganizationId, GameNumber), -- Composite PRIMARY KEY.
CONSTRAINT SystemGameToSystem_FK FOREIGN KEY (SystemOrganizationId, SystemNumber) -- Multi-column FOREIGN KEY.
REFERENCES MySystem (OrganizationId, SystemNumber),
CONSTRAINT SystemGameToGame_FK FOREIGN KEY (SystemOrganizationId, GameNumber) -- Multi-column FOREIGN KEY.
REFERENCES Game (OrganizationId, GameNumber)
);
CREATE TABLE GameGenre ( -- Denotes an associative entity type or M:N association.
GameOrganizationId INT NOT NULL,
GameNumber INT NOT NULL,
GenreNumber INT NOT NULL,
CreatedDateTime DATETIME NOT NULL,
--
CONSTRAINT GameGenre_PK PRIMARY KEY (GameOrganizationId, GameNumber, GenreNumber), -- Composite PRIMARY KEY.
CONSTRAINT GameGenreToGame_FK FOREIGN KEY (GameOrganizationId, GameNumber)
REFERENCES Game (OrganizationId, GameNumber), -- Multi-column FOREIGN KEY.
CONSTRAINT GameGenreToGenre_FK FOREIGN KEY (GenreNumber)
REFERENCES Genre (GenreNumber)
);
CREATE TABLE Job ( -- Stands for an associative entity type or M:N association.
OrganizationId INT NOT NULL,
ProductNumber INT NOT NULL,
JobNumber INT NOT NULL,
Title CHAR(30) NOT NULL,
CreatedDateTime DATETIME NOT NULL,
--
CONSTRAINT Job_PK PRIMARY KEY (OrganizationId, ProductNumber, JobNumber), -- Composite PRIMARY KEY.
CONSTRAINT Job_AK UNIQUE (Title), -- Single-column ALTERNATE KEY.
CONSTRAINT JobToProduct_FK FOREIGN KEY (OrganizationId, ProductNumber) -- Multi-column FOREIGN KEY.
REFERENCES Product (OrganizationId, ProductNumber)
);
CREATE TABLE Collaborator ( -- Represents an associative entity type or M:N association.
CollaboratorId INT NOT NULL,
OrganizationId INT NOT NULL,
ProductNumber INT NOT NULL,
JobNumber INT NOT NULL,
AssignedDateTime DATETIME NOT NULL,
--
CONSTRAINT Collaborator_PK PRIMARY KEY (CollaboratorId, OrganizationId, ProductNumber, JobNumber), -- Composite PRIMARY KEY.
CONSTRAINT CollaboratorToPerson_FK FOREIGN KEY (CollaboratorId)
REFERENCES Person (PersonId),
CONSTRAINT CollaboratorToJob_FK FOREIGN KEY (OrganizationId, ProductNumber, JobNumber) -- Multi-column FOREIGN KEY.
REFERENCES Job (OrganizationId, ProductNumber, JobNumber)
);
Es oportuno enfatizar que existen declaraciones de restricciones PRIMARY KEY compuestas en varias tablas, que representan la jerarquía de conexiones que tienen lugar entre los tipos de entidades conceptuales, disposición que puede ser muy beneficiosa con respecto a la recuperación de datos cuando, por ejemplo, se expresa SELECT operaciones que incluyen cláusulas JOIN para obtener tablas derivadas .
Sí, (i) cada asociación M: N y (ii) cada uno de los tipos de entidad asociados se denota por (iii) la tabla correspondiente en la estructura lógica DDL, por lo tanto, preste especial atención a las restricciones PRIMARY y FOREIGN KEY (y la notas que dejé como comentarios) de las tablas que representan estos elementos conceptuales, porque ayudan a garantizar que las conexiones entre las filas relevantes cumplan con las proporciones de cardinalidad aplicables.
El Dr. EF Codd introdujo el uso de claves compuestas desde el origen mismo del paradigma relacional, como se demostró en los ejemplos que incluyó en su artículo seminal de 1970 titulado Un modelo relacional para grandes bancos de datos compartidos (que, precisamente, también presenta el método más elegante para manejar asociaciones conceptuales M: N).
Puse un db <> fiddle y un SQL Fiddle , ambos ejecutándose en Microsoft SQL Server 2014, para que la estructura se pueda probar "en acción".
Normalización
La normalización es un procedimiento de nivel lógico que implica, básicamente hablando:
Eliminando columnas no atómicas a través de la primera forma normal para que la manipulación de datos y la constricción sean mucho más fáciles de manejar mediante el sublenguaje de datos de uso (por ejemplo, SQL).
Deshacerse de las dependencias indeseables entre las columnas de una tabla específica en virtud de las formas normales sucesivas para evitar anomalías de actualización .
Naturalmente, uno tiene que tener en cuenta el significado que tienen las tablas y las columnas en cuestión.
Me gusta pensar en la normalización como una prueba fundada en la ciencia que un diseñador aplica a los elementos pertinentes una vez que ha delineado una disposición estable de nivel lógico para determinar si sus elementos cumplen con cada una de las formas normales o no. Luego, si es necesario, el diseñador toma las medidas correctivas apropiadas.
Redundancia
En el modelo relacional, aunque la duplicación de valores contenidos en columnas no solo es aceptable sino esperada , las filas duplicadas están prohibidas . En esa medida, hasta donde puedo ver, se evitan filas duplicadas y otros tipos de redundancias dañinas en todas las tablas comprendidas en el diseño lógico expuesto anteriormente, tal vez le gustaría aclarar su preocupación a este respecto.
De todos modos, ciertamente puede (a) evaluar su propia estructura a fuerza de las formas normales para definir si cumple con los requisitos y (b) modificarla si es necesario.
Recursos Relacionados
- En esta serie de mensajes presento algunas deliberaciones sobre un M sencillo: asociación N que puede interrelacionar los casos de dos diferentes tipos de entidad.
- En este otro , propongo un enfoque para manejar una ocurrencia de la construcción "Lista de materiales" o "Explosión de piezas", en la que describo cómo conectar instancias distintas del mismo tipo de entidad.
Asociaciones ternarias
Hay otro aspecto importante que mencionó a través de comentarios (publicado en una respuesta ahora eliminada):
Cada vez que intento hacer un puente, los elementos en ese puente también tienen un Muchos a Muchos, tengo la impresión de que no está permitido o al menos desalentado.
Esa circunstancia parece indicar que una de sus preocupaciones tiene que ver con asociaciones ternarias conceptuales . Básicamente hablando, este tipo de asociaciones se produce cuando existe (1) una relación que involucra (2) otras dos relaciones, en otras palabras, "una relación entre relaciones", una situación típica también, ya que una relación es una entidad en sí misma -.
Estas disposiciones, cuando se gestionan adecuadamente, tampoco generan redundancias perjudiciales. Y, sí, si hay un cierto caso de uso en el que identifica que tales relaciones se presentan entre los tipos de entidades del "mundo real", debe (i) modelar y (ii) declararlas con precisión en el nivel lógico.
- Aquí hay una pregunta y respuesta donde analizamos un dominio del discurso sobre las encuestas , que incluye un ejemplo de asociación ternaria.
- En esta muy buena respuesta , @Ypercube presenta un diagrama y la estructura DDL respectiva para una interesante relación en forma de diamante , que es muy similar a esta clase de escenarios.