Projetando um banco de dados para um domínio comercial de videogame com vários relacionamentos muitos-para-muitos


16

Sou relativamente novo no design de bancos de dados e decidi criar meu próprio banco de dados hipotético para a prática. No entanto, estou tendo problemas para modelá-lo e normalizá-lo, pois considero que existem inúmeras relações muitos-para-muitos (M: N).

Descrição geral do cenário

O banco de dados tem como objetivo reter dados sobre várias pessoas que trabalharam na série Zelda. Eu quero manter o controle dos console (s) que um jogo pode ser jogado em, funcionários que tiveram um papel no Jogos de desenvolvimento, o emprego do empregado tinha (muitos funcionários trabalhou em diferentes empregos em vários jogos ), etc.

Regras do negócio

  • Vários funcionários podem trabalhar em vários jogos .
  • Vários jogos podem estar no mesmo console .
  • Vários consoles podem ser uma plataforma para o mesmo jogo .
  • Vários funcionários podem ter o mesmo trabalho .
  • Um funcionário pode ter vários trabalhos .
  • Um jogo pode ter vários funcionários .
  • Um jogo pode ter vários tipos de trabalhos em seu desenvolvimento
  • Vários jogos podem ter o mesmo tipo de trabalho anexado.
  • Um console pode ter várias pessoas trabalhando nele.
  • Uma pessoa pode trabalhar em vários consoles .

Nomes de atributos e valores de amostra

  • Nome do funcionário , que pode ser dividido em primeiro e último (por exemplo, "John" e "Doe")
  • Título do jogo (por exemplo, "Ocarina of Time")
  • Cargo (por exemplo, "Design de nível", "Diretor", "Composição", "Designer de nível", "Programador", "Localização" etc.).
  • Nome do console (por exemplo, "Game Boy Advance")

O problema

Até o momento, parece que não importa o que eu projete, existem redundâncias de dados e relacionamentos M: N entre os tipos de entidade de interesse em todos os lugares. No entanto, eu sinto que os designers de banco de dados precisam enfrentar esse tipo de problema o tempo todo, portanto, deve haver uma solução.


Nota : Consigo encontrar os dados para preencher a tabela, o problema é organizá-los em um banco de dados com tabelas em um formulário normalizado.


11
Os comentários foram movidos para uma sala de bate-papo, conforme solicitado.
Paul White Reinstate Monica

Respostas:


18

Sim, a identificação de associações ou relacionamentos muitos-para-muitos (M: N por questões de brevidade) é uma situação que um profissional de banco de dados enfrenta com bastante frequência ao definir um esquema conceitual. As associações das referidas taxas de cardinalidade ocorrem em ambientes de negócios de natureza muito diferente e, quando adequadamente representadas no nível lógico por meio de, por exemplo, um arranjo SQL-DDL, elas não introduzem redundâncias prejudiciais.

Dessa maneira, o objetivo de um exercício de modelagem de banco de dados deve ser o de espelhar as características relevantes do contexto de negócios de interesse com alta precisão ; portanto, se você identificar corretamente que existem inúmeras associações M: N, deverá expressá-las em (a) o esquema conceitual e também em (b) nas respectivas declarações de nível lógico, não importando quantas conexões disso - ou nenhuma outros tipos de taxas de cardinalidade devem ser abordados.

Regras do negócio

Você forneceu uma pergunta bem contextualizada e também esclareceu que o banco de dados em que está trabalhando é puramente hipotético, o que é um ponto importante, pois considero que um cenário de negócios do “mundo real” como o que está sendo considerado seria muito mais extenso e, portanto, implicaria requisitos informativos mais complexos.

Decidi (1) fazer algumas modificações e ampliações nas regras de negócios que você forneceu para (2) produzir um esquema conceitual mais descritivo - embora ainda bastante hipotético -. Aqui estão algumas das formulações que montei:

  • Uma Parte 1 é uma Pessoa ou uma Organização
  • Uma Parte é classificada por exatamente um PartyType
  • A PartyType classifica Zero-um-ou-muitas partes
  • Uma Organização desenvolve de zero-um ou-muitos produtos
  • Um produto é um sistema ou um jogo
  • Um produto é classificado por exatamente-um ProductType
  • Um sistema é catalogado por exatamente um SystemType
  • Um jogo pode ser jogado através de sistemas um para muitos
  • Um sistema é usado para jogar um-para-muitos Games
  • Um jogo é classificado por zero ou um gêneros
  • Um gênero classifica zero-one-or-many Games
  • Um produto é originário de um-para-muitos Jobs
  • Um Job é cumprida por zero-um-ou-muitas pessoas , que estão jogando o papel de Colaboradores
  • Uma pessoa é um colaborador no zero-um ou-muitas Jobs

1 Parte é um termo usado em contextos legais quando se refere a um indivíduo ou a um grupo de indivíduos que compõem uma única entidade; portanto, essa denominação é adequada para representar Pessoas e Organizações .


Diagrama IDEF1X

Posteriormente, criei o diagrama IDEF1X 2 mostrado na Figura 1 (certifique-se de clicar no link para vê-lo em uma resolução mais alta), consolidando em um único dispositivo gráfico as regras de negócios apresentadas acima (juntamente com outros que parecem relevantes):

Figura 1 - Diagrama do Video Gae Jobs IDEF1X


2 Definição de integração para modelagem de informações ( IDEF1X ) é uma técnica de modelagem de dados altamente recomendável que foi estabelecida como padrão em dezembro de 1993 pelo Instituto Nacional de Padrões e Tecnologia (NIST) dos Estados Unidos . É baseado em (a) o material teórico inicial criado pelo único autor do modelo relacional, ou seja, Dr. EF Codd; (b) a visão de dados de relacionamento entre entidades , desenvolvida pelo Dr. PP Chen ; e também (c) a Logical Database Design Technique, criada por Robert G. Brown.


Como você pode ver, eu descrevi apenas três associações M: N por meio dos tipos de entidade associativa correspondentes , ou seja:

  • Colaborador
  • SystemGame
  • GameGenre

Entre outros aspectos, existem duas estruturas distintas de supertipo-subtipo , onde:

  • Pessoa e Organização são subtipos de entidade mutuamente exclusivos da Parte , seu supertipo de entidade

  • Produto é o supertipo de Sistema e jogo , que por sua vez são subtipos mutuamente exclusivos

Caso você não esteja familiarizado com associações de supertipo-subtipo, poderá encontrar ajuda, por exemplo, minhas respostas para as perguntas intituladas:

Layout SQL-DDL lógico ilustrativo

Sucessivamente, devemos garantir que, no nível lógico:

  • Cada tipo de entidade é representado por uma tabela base individual
  • Cada propriedade única do tipo de entidade aplicável é indicada por uma coluna específica
  • Um tipo exato de dados é fixado para cada coluna , a fim de garantir que todos os valores contidos pertençam a um conjunto específico e bem definido, seja INT, DATETIME, CHAR, etc. (é claro, ao usar, por exemplo, Firebird ou PostgreSQL , você pode empregar os DOMAINs mais poderosos)
  • Múltiplas restrições são configuradas (declarativamente) para garantir que as asserções em forma de linhas retidas em todas as tabelas estejam em conformidade com as regras de negócios determinadas no nível conceitual

Por isso, declarei o seguinte arranjo DDL com base no 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)
);

É oportuno enfatizar que há declarações de restrições compostas PRIMARY KEY em várias tabelas, que representam a hierarquia de conexões que ocorrem entre os tipos conceituais de entidades, arranjo que pode ser muito benéfico em relação à recuperação de dados quando, por exemplo, expressar SELECT operações que incluem cláusulas JOIN para obter tabelas derivadas .

Sim, (i) todas as associações M: N e (ii) todos os tipos de entidades associadas são denotados pela (iii) tabela correspondente na estrutura DDL lógica, portanto, preste atenção especial às restrições PRIMARY e FOREIGN KEY (e as observa que deixei como comentários) de tabelas que representam esses elementos conceituais, porque ajudam a garantir que as conexões entre as linhas relevantes atendam às taxas de cardinalidade aplicáveis.

O uso de chaves compostas foi introduzido pelo Dr. EF Codd desde a origem do paradigma relacional, como demonstrado nos exemplos que ele incluiu em seu artigo seminal de 1970 intitulado Um modelo relacional para grandes bancos de dados compartilhados (que, precisamente, também apresenta o método mais elegante para lidar com associações conceituais M: N).

Coloquei um db <> fiddle e um SQL Fiddle , ambos em execução no Microsoft SQL Server 2014, para que a estrutura possa ser testada "em ação".

Normalização

A normalização é um procedimento de nível lógico que implica, basicamente falando:

  1. Eliminar colunas não atômicas através da primeira forma normal, para que a manipulação e constrição de dados sejam muito mais fáceis de lidar com a sub-linguagem de dados de uso (por exemplo, SQL).

  2. Livrar-se de dependências indesejáveis entre as colunas de uma tabela específica em virtude dos sucessivos formulários normais para evitar anomalias de atualização .

Naturalmente, é preciso levar em consideração o significado da tabela (s) e coluna (s) em questão.

Gosto de pensar na normalização como um teste baseado na ciência que um designer aplica aos elementos pertinentes depois de delinear um arranjo estável de nível lógico para determinar se seus itens estão de acordo com todas as formas normais ou não. Então, se necessário, o designer toma as medidas de correção apropriadas.

Redundância

No modelo relacional, enquanto a duplicação de valores contidos nas colunas não é apenas aceitável, mas esperada , as linhas duplicadas são proibidas . Nessa medida, até onde posso ver, linhas duplicadas e outros tipos de redundâncias prejudiciais são impedidos em todas as tabelas incluídas no layout lógico exposto anteriormente, talvez você queira esclarecer sua preocupação a esse respeito.

De qualquer forma, você pode certamente (a) avaliar por conta própria a referida estrutura com base nas formas normais para definir se ela atende aos requisitos e (b) modificá-la se necessário.

Recursos relacionados

  • Em esta série de posts apresento algumas deliberações sobre um M simples: associação N que podem se inter-relacionam os casos de dois diferentes tipos de entidade.
  • Em este outro proponho uma abordagem para lidar com uma ocorrência do “Bill of Materials” ou construção “Peças de explosão”, em que descrevem como conectar distintas instâncias do mesmo tipo de entidade.

Associações ternárias

Há outro aspecto importante que você mencionou por meio de comentários (publicado em uma resposta agora excluída):

Toda vez que tento fazer uma ponte, os elementos nessa ponte também têm muitos para muitos, tenho a impressão de que não é permitido ou pelo menos desencorajado.

Essa circunstância parece indicar que uma de suas preocupações tem a ver com associações ternárias conceituais . Basicamente, esse tipo de associação ocorre quando existe (1) um relacionamento envolvendo (2) dois outros relacionamentos, ou seja, "um relacionamento entre relacionamentos" - uma situação típica também, já que um relacionamento é uma entidade por si só. -.

Esses arranjos, quando adequadamente gerenciados, também não trazem redundâncias prejudiciais. E, sim, se houver um certo caso de uso em que você identifique que esses relacionamentos se apresentam entre os tipos de entidades do "mundo real", é necessário (i) modelar e (ii) declará-los com precisão no nível lógico.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.