Assessoria em um design básico, design de banco de dados inicial

8

Estou fazendo um curso para me tornar um desenvolvedor Java.

O curso envolve o uso de bancos de dados, mas nunca projetamos nenhum, infelizmente.

Na maioria das vezes, obtemos bancos de dados pré-fabricados e precisamos implementar código para inserir, atualizar, ler ou excluir dados.

Porém, quando meu teste final chegar, é provável que eu esteja criando algo que envolva um banco de dados e, portanto, tente criar alguns pequenos para entender o design, pois notei que um bom design de banco de dados faz muita diferença quando escrevendo o código para trabalhar com ele.

Espero que este tipo de perguntas seja permitido aqui e que não seja muito amplo.


Este é um design pequeno que fiz para algo simples como clubse memberscom addressese phonenumbers.

  • Haverá vários clubes.
  • Cada clube terá vários sócios (óbvio)
  • Um associado não pode fazer parte de vários clubes
  • Um membro pode ter vários números de telefone e endereços de email
  • Um membro pode ter apenas um endereço
  • Um endereço pode pertencer a diferentes membros (casais ou irmãos)

Minhas maiores confusões:

  • Se eu quiser adicionar uma coluna Clubque descreva o proprietário, que também será membro, qual é a melhor abordagem sem ter o mesmo membro listado duas vezes?

  • Devo colocar todas as minhas tabelas no incremento automático de um ID ou isso seria uma má idéia? (vantagens / desvantagens?)

  • Se eu adicionar chaves estrangeiras na guia Chaves estrangeiras, elas corresponderão automaticamente à tabela correta ou também devo adicioná-las às colunas? (ver figura 2)

  • E minha pergunta provavelmente mais nobre ... Coloco as chaves estrangeiras de phonenumbere emailna respectiva tabela vinculadas a uma person_Id ou devo colocar phoneNumber e IDs de email na tabela de pessoas?

(Minhas desculpas pelo idioma nas fotos não ser inglês, espero que isso não seja um problema)

Projeto

Chaves estrangeiras

Vahx
fonte

Respostas:

11

Respostas às suas perguntas individuais

Se eu quiser adicionar uma coluna Clubque descreva o proprietário, que também será membro, qual é a melhor abordagem sem ter o mesmo membro listado duas vezes?

Se, como indicado em suas especificações a Person can be a Member of only one Club, e você estiver interessado em armazenar esse dado simplesmente como verdadeiro ou falso , uma opção é adicionar uma coluna BIT(1)ou uma BOOLEAN( TINYINT) à Persontabela e você pode chamá-la IsClubOwner. Dessa forma, você pode registrar o fato de que uma determinada pessoa é dona de um clube exclusivamente uma vez. Além disso, esse método também permite manter várias pessoas como donos da mesma ocorrência de clube . Você pode ver uma representação em nível lógico dessa abordagem na Figura 1 .

No entanto, você está procurando a melhor abordagem e, de acordo com minha experiência, essa abordagem implica o desenvolvimento de uma estrutura muito mais expansível e versátil. A esse respeito, siga a progressão de um exercício de modelagem para esses e outros pontos abaixo, nas seções intituladas “Cobrindo suas especificações restantes”, “Pessoa como membro de vários clubes” e “Membro e proprietário como tipos de entidade separados”.

Devo colocar todas as minhas tabelas no incremento automático de uma idou isso seria uma má idéia? (benefícios / desvantagens?)

Se você enfrentar um requisito explícito que indica a definição de uma tabela com uma coluna com essas características, e essa coluna tiver um significado contextual válido ou servir a um propósito específico, como ser um substituto para uma ampla PRIMARY KEY (PK) natural, então sim, você deve proceder dessa maneira.

Caso contrário, se você não tiver dito esse requisito, considero desnecessário, pois é necessário armazenar e gerenciar uma coluna extra sem sentido e (talvez?) Também um índice adicional em seu banco de dados.

Como sempre, você deve analisar cada caso, juntamente com suas repercussões gerais, a fim de decidir como prosseguir.

Se eu adicionar chaves estrangeiras na guia Chaves estrangeiras, elas corresponderão automaticamente à tabela correta ou também devo adicioná-las às colunas?

Nesse sentido, meu conselho para você é criar sua estrutura de banco de dados manualmente, codificar suas próprias DDLdeclarações até obter uma compreensão firme do assunto. Se você fizer isso, será mais fácil entender os processos que as ferramentas gráficas estão executando "sob o capô".

Para mim, por exemplo, criando uma declaração como a seguinte:

CONSTRAINT FK_PersonPhoneNumber_to_Person FOREIGN KEY (PersonId)
REFERENCES Person (PersonId)

É muito mais instrutivo do que usar ferramentas da GUI para executar esse tipo de tarefas, especialmente agora que você está criando seus primeiros projetos.

E minha pergunta provavelmente a mais nobre de todas ... Coloco as chaves estrangeiras de phone_numbere emailna respectiva tabela vinculadas a uma person_idou devo colocar phone_numbere email idsna tabela de pessoas?

Pessoalmente, acho que essa e todas as suas outras perguntas são completamente válidas e bem contextualizadas .

Voltando aos aspectos técnicos que nos interessam, essa investigação precisa oferece uma boa oportunidade para revisar as duas afirmações a seguir:

  • A Person can be reached through zero-one-or-many PhoneNumbers
  • A PhoneNumber can be used to reach one-to-many People

Portanto, pode-se concluir que há um relacionamento muitos-para-muitos entre Persone PhoneNumber, portanto, sugiro a criação de uma tabela associativa nomeada PersonPhoneNumberpara representar o referido relacionamento em seu banco de dados. A PK desta tabela deve ser composta por duas colunas diferentes: PersonId(uma CHAVE ESTRANGEIRA [FK] apontando para Person.PersonId) e PhoneNumber(uma FK que faz referência a PhoneNumber.Number). Para uma descrição do nível lógico de todas as opções acima, consulte a Figura 1 .

Por outro lado, vamos examinar as duas proposições a seguir:

  • A Person can be contacted via zero-one-or-many EmailAddresses
  • An EmailAddress can be used to contact exactly one Person

Então, sim, você deve definir uma referência de FK a Personpartir da EmailAddresstabela, e essa tabela também deve ter uma PK composta, que seria composta pelas colunas PersonIde Address. Dessa maneira, você pode garantir que a mesma combinação EmailAddress.PersonIde EmailAddress.Addresspossa ser inserida apenas uma vez.

Se você também deseja garantir que um dado EmailAddres.Addresspossa ser armazenado em uma única linha, basta estabelecer uma Restrição Única para esta coluna.

Modelos de dados lógicos propostos

Para expor minhas sugestões com mais clareza, incluí quatro modelos lógicos distintos do IDEF1X [1] que são mostrados na Figura 1 , Figura 2 , Figura 3 e Figura 4 . Fornecerei uma explicação dos recursos mais relevantes exibidos em cada um deles nas seções correspondentes. Você também pode baixar do Dropbox um PDF que integra em um único modelo a maioria dos elementos em discussão.

Cobrindo suas especificações restantes

Relacionando pessoas e endereços

Vamos examinar as duas seguintes afirmações (ligeiramente reformuladas) que são relevantes para pessoas e endereços :

  • A Person can only have one Address
  • An Address can belong to different People (couples or siblings)

Portanto, para lidar com essas restrições, você pode optar por implementar um modelo de dados semelhante ao que você pode ver na Figura 1 .

Fig. 1. Modelo de dados de clubes e associados - primeiras especificações

Levando em conta o modelo referido, você deve seguir os próximos passos:

  1. Crie uma tabela chamada PersonAddresscorrigindo um relacionamento entre Persone Address. Defina as colunas PersonIde AddressIdcomo o PK composto desta tabela.

  2. Configure um CONSTRAINT UNIQUE para a PersonAddress.PersonIdcoluna para garantir que um valor específico possa ser inserido em no máximo uma linha da referida tabela. No nível lógico, essa circunstância implica que PersonAddress.PersonIdse tornou uma CHAVE ALTERNATIVA [2] .

  3. Se o valor de AddressIduma determinada PersonAddresstentativa de inserção ainda não estiver armazenado, deixe a inserção continuar; caso contrário, quando esse valor já existir em uma linha, você deverá verificar se (a) PersonIdquem registrou AddressIdtambém está registrado como o Marriage.WifeIdse o PersonIdé um homem (dado derivado do Person.GenreCode) ou (b) que PersonIdé o Marriage.HusbandIdquando o PersonIdé uma mulher (derivada também em virtude de Person.GenreCode). Se uma dessas condições for atendida na situação apropriada, você deverá deixar o INSERT continuar.

  4. Se as condições acima não foram cumpridas, ainda há uma chance de uma PersonAddresstentativa de inserção ser bem-sucedida. Você deve verificar se o PersonIdvalor envolvido na inserção inserida compartilha pelo menos um Progeny.ParentIdcom o PersonIdque já registrou o PersonAddress.AddressId. Se essa condição for atendida, significa que eles são armazenados como Siblingsno banco de dados, portanto, este INSERT deve ser bem-sucedido.

Como em qualquer implementação de banco de dados relacional, considere seriamente executar suas DMLoperações nas transações do ACID, para proteger a integridade e a consistência dos dados com os quais você está trabalhando.

Atender aos requisitos que você adicionou nos comentários: Endereços e números de telefone que atendem igualmente a clubes e pessoas

Desde que você deseje que os endereços e números de telefone sirvam pessoas e clubes , você pode usar um relacionamento de supertipo-subtipo . Aqui está uma resposta na qual dou um tratamento mais detalhado a esse tipo de estrutura, caso você esteja interessado.

No cenário atual, você pode definir Persone Clubcomo subtipos de uma nova entidade denominada Party, um termo comumente usado em círculos jurídicos para representar (a) uma pessoa ou (b) um grupo de pessoas (conforme observado no sentido 6 ). Com esse método, os relacionamentos entre Addresses(ou PhoneNumbers) e Peoplee Clubsseriam definidos por meio Partydo supertipo. Veja a Figura 2 para uma representação desta sugestão.

Fig. 2. Modelo de Dados de Clubes e Associados - Segunda Especificações

Parte e endereço

Então, podemos ler neste novo modelo que:

  • A Party keeps zero-one-or-many Addresses
  • An Address is kept by one-to-many Parties

Assim, há um relacionamento muitos-para-muitos envolvendo Partye Addressque é expresso por meio da PartyAddressentidade.

Party and PhoneNumber

Além disso, podemos interpretar que:

  • A Party is reached through zero-one-or-many PhoneNumbers
  • A PhoneNumber is used by one-to-many Parties

Por isso, adicionei a PartyPhoneNumberentidade que descreve a associação muitos-para-muitos que entra em vigor entre os tipos de entidade Partye PhoneNumber.

Parte e clube ou pessoa

Então, também pode ser lido que:

  • A Party is either a Club or a Person

Por conseguinte, Partyfornece uma ligação de um ou outro Clubs ou People para Addresses(ou PhoneNumbers).

Pessoa como membro de vários clubes

Como @aldwinaldwin menciona em sua resposta, se você deseja fornecer a funcionalidade para uma pessoa ser membro de vários clubes , pode incluir uma tabela chamada ClubMemberque estaria agindo como outro relacionamento de muitos para muitos, desta vez naturalmente , interconectando Persone Club.

Acrescentarei ao exposto que esta tabela também pode ser útil no objetivo de armazenar qualquer pessoa concreta como proprietária de vários clubes , por meio da inclusão da IsClubOwnercoluna booleana já mencionada . De fato, pode-se dizer que esta nova tabela é a representação de um tipo de entidade integral por direito próprio.

Como demonstrado na Figura 3 , essa tabela requer uma PK composta composta pelas colunas ClubIde MemberId(um nome de função [3] dado a PersonId), e essas colunas devem ser definidas também como FKs apontando, correspondentemente, para Clube Person.

Fig. 3. Modelo de Dados de Clubes e Sócios - Pessoa como Sócio de Múltiplos Clubes

Uma estrutura mais adaptável

Empregando essa configuração, você também pode cumprir a regra inicial que declara isso a Person can be a member of only one Club, mas você só precisa adicionar uma restrição exclusiva à MemberIdcoluna, para que um determinado valor possa ser inserido em mais de uma ocasião. Portanto, como você pode observar, essa estrutura é muito mais adaptável que a mostrada na Figura 1 , uma vez que, ao descartar o UNIQUE CONSTRAINT (ou INDEX), você abriria a funcionalidade mencionada acima, de permitir que uma pessoa se torne membro de diferentes clubes do clube. mesmo tempo.

Membro e Proprietário como tipos de entidade separados

Como você sabe, o armazenamento de vários fatos sobre o papel desempenhado por uma pessoa como proprietário de um clube - além de sua mera existência em um atributo verdadeiro ou falso - pode ser muito vantajoso. Por exemplo, convém manter a data efetiva em que uma pessoa definida se tornou proprietária de um clube ; portanto, você pode gerenciar essa situação introduzindo um tipo de entidade separado chamado ClubOwner, conforme apresentado na Figura 4 .

Fig. 4. Modelo de dados de clubes e associados - membro e proprietário como tipos de entidade separados

Depois de criar uma tabela com base nesse novo tipo de entidade, você pode adicionar as colunas de ajuste que representam as características que entram em jogo exclusivamente quando a Personé a Ownerde a Club. Conforme representado, esta tabela conteria uma PK composta pelas colunas FK referenciadas Person.PersonIde Club.ClubId, dessa forma, qualquer combinação de ClubOwner.OwnerId(ou ClubOwner.PersonId, se preferir) e ClubOwner.ClubIdpode ser inserida em apenas uma oportunidade.

Obviamente, com essa configuração, você ainda pode derivar em forma booleana se a Personé Owneruma particularidade Clubcom o auxílio de uma consulta que retorna um valor escalar que pode ser avaliado como verdadeiro ou falso .


Notas

1. A Definição de Integração para Modelagem de Informações ( IDEF1X ) é uma técnica de modelagem de dados altamente recomendável que foi definida como padrão em dezembro de 1993 pelo Instituto Nacional de Padrões e Tecnologia dos Estados Unidos ( NIST ). É solidamente baseada em (a) alguns dos trabalhos teóricos de autoria do criador do modelo relacional , isto é, Dr. EF Codd ; na (b) teoria da Entidade-Relacionamento , desenvolvida pelo Dr. PP Chen ; e também (c) a Logical Database Design Technique , criada por Robert G. Brown . Vale ressaltar que o IDEF1X foiformalizado por meio de lógica de primeira ordem .

2. Uma CHAVE ALTERNATIVA é um atributo (ou uma combinação de atributos) que contém valores que identificam exclusivamente uma ocorrência de entidade, mas não foram escolhidos como a PK do tipo de entidade pertinente; cada tipo de entidade pode ter zero, uma ou mais CHAVES ALTERNATIVAS. Num modelo IDEF1X, eles são são indicados como “AK” para além do seu respectivo número, por exemplo, AK1, AK2, etc. Eles são geralmente implementadas em um SQL DDL estrutura através de uma restrição exclusiva (ou um UNIQUE INDEX ).

3. Os nomes das funções são denotações (ou aliases) atribuídos aos atributos do FK, a fim de expressar o significado que eles possuem no escopo de sua respectiva entidade. Seu uso é recomendado desde 1970 pelo Dr. Codd em seu artigo seminal intitulado "Um modelo relacional de dados para grandes bancos de dados compartilhados" . Por sua vez, o IDEF1X - mantendo a fidelidade em relação às práticas relacionais - também defende a nomeação de funções.

MDCCL
fonte
2
  1. Se um proprietário é sempre um membro de seu clube. Adicione o ownerId à tabela Club e coloque o personId no membro que é o proprietário.
  2. O incremento automático de um ID é bom. Você pode adicionar outro campo 'código', lá você coloca o código do associado no cartão do clube.
  3. Deve estar automaticamente ok (eu acho)
  4. Coloque personId em números de telefone e tabela de e-mail.

... Você não pode ser membro de vários clubes? Se puder, crie uma tabela ClubMember com clubId e personId. Dessa forma, você pode conectar uma pessoa a vários clubes.

aldwinaldwin
fonte
11
E se eu quiser que meu clube tenha um número de telefone também? introduzo clubIdtambém o número de telefone e deixo o clube ou a pessoa definida como nula?
Vahx
Eu não 'separaria' todos os objetos (normalização de dados). Basta colocar 1 número de telefone na mesa do clube. A normalização é boa, mas muita normalização pode causar problemas.
Aldwinaldwin
11
mas suponha que eu queira fazer isso? eu tomarei endereço como exemplo, o membro tem um endereço mas os clubes também vai precisar de um endereço
Vahx
11
Crie um registro de endereço e coloque o addressId no clube. Como um clube tem 1 endereço, um sócio tem 1 endereço. Para números de telefone, você precisa colocar personId no registro de número de telefone para ter 1 a muitos. ..... Você pode criar uma tabela personPhoneNumber (personId, phonenumberId) + tabela clubPhoneNumber (clubId, phonenumberId), o que torna mais um relacionamento muitos-muitos.
Aldwinaldwin