INTRODUÇÃO E INFORMAÇÕES RELEVANTES:
O exemplo a seguir ilustra o problema que enfrento:
O animal tem uma raça, que pode ser um gato ou um cachorro . O gato pode ser siamês ou persa . O cão pode ser um pastor alemão ou um retriever de Labrador .
O animal é uma entidade forte, enquanto sua raça é um atributo que pode ter um dos dois valores oferecidos (gato ou cachorro). Ambos os valores são complexos (adicionei aqui apenas o tipo de cachorro / gato para ilustrar o problema, mas também pode haver o nome do gato / cachorro e várias outras coisas).
PROBLEMA:
Não sei como criar tabelas relacionais para este exemplo.
MEUS ESFORÇOS PARA RESOLVER O PROBLEMA:
Tentei desenhar o diagrama de ER, usando a notação de Chen, que representa o problema, mas sendo um iniciante, não sei se fiz direito. Aqui está o que eu tenho:
Peço desculpas se desenhei algo errado, por favor, corrija-me se for esse o caso. Não desejo simplesmente obter "solução gratuita", mas também aprender a lidar com esse problema para que eu possa resolvê-lo sozinho no futuro.
A única coisa que me vem à cabeça é criar duas tabelas separadas, uma para gatos e outra para cães. Além disso, o atributo de corrida na tabela Animal armazenaria apenas o valor de gato ou cachorro . Algo assim:
Animal< # Animal_ID, race, other attributes >
Cat < # Cat_ID, $ Animal_ID, breed >
Dog < # Dog_ID, $ Animal_ID, breed >
Eu realmente tenho um mau pressentimento sobre minha solução e temo que esteja errado, daí a pergunta abaixo.
QUESTÕES:
- Como posso transformar meu exemplo em diagrama de ER?
- Como transformar esse diagrama de ER em tabelas relacionais?
Se mais informações forem necessárias, deixe um comentário e atualizarei minha postagem o mais rápido possível. Também sinta-se à vontade para adicionar tags apropriadas, pois sou bastante novo aqui.
Obrigado.
fonte
Respostas:
A estrutura apropriada para esse cenário é um modelo de subclasse / herança e é quase idêntica ao conceito que propus nesta resposta: Lista de valores ordenados heterogêneos .
O modelo proposto nesta questão é bastante próximo, pois a
Animal
entidade contém o tipo (ou sejarace
) e as propriedades comuns a todos os tipos. No entanto, existem duas pequenas alterações necessárias:Remova os campos Cat_ID e Dog_ID de suas respectivas entidades:
O conceito chave aqui é que tudo é um
Animal
, independentementerace
:Cat
,Dog
,Elephant
, e assim por diante. Dado que o ponto de partida, qualquer particular,race
deAnimal
não realmente precisa de um identificador separado desde:Animal_ID
é únicoCat
,,Dog
e quaisquerrace
entidades adicionais adicionadas no futuro, por si só, não representam totalmente nenhum detalheAnimal
; apenas têm significado quando utilizados em combinação com as informações contidas na entidade - mãeAnimal
.Assim, a
Animal_ID
propriedade noCat
,Dog
, etc entidades é tanto o PK e as costas FK àAnimal
entidade.Diferencie entre tipos de
breed
:Só porque duas propriedades compartilham o mesmo nome não significa necessariamente que essas propriedades são iguais, mesmo que o nome que seja o mesmo implique esse relacionamento. Nesse caso, o que você realmente tem é realmente
CatBreed
eDogBreed
como "tipos" separadosNotas iniciais
VARCHAR
mas se você precisar armazenar algo fora do conjunto ASCII padrão, você deve realmente usá-loNVARCHAR
.Race
,CatBreed
eDogBreed
) são não (ou seja, IDENTIDADE, em termos de T-SQL) auto-incremental, porque eles são constantes aplicação (ou seja, são parte da aplicação) que são valores de pesquisa estáticos no banco de dados e são representados comoenum
s em C # (ou em outros idiomas). Se valores são adicionados, eles são adicionados em situações controladas. Reservo o uso de campos de incremento automático para dados do usuário que chegam através do aplicativo."Raça" como abordagem específica de "raça"
Este primeiro conjunto de tabelas são as tabelas de pesquisa / tipos:
Esta segunda listagem é a principal entidade "Animal":
Este terceiro conjunto de tabelas são as entidades de subclasse complementares que completam a definição de cada um
Race
dos seguintesAnimal
:O modelo que usa um
breed
tipo compartilhado é mostrado após a seção "Notas adicionais".Notas Adicionais
breed
parece ser um ponto focal de confusão. Foi sugerido por jcolebrand (em um comentário sobre a pergunta) quebreed
é uma propriedade compartilhada entre os diferentesrace
s, e as outras duas respostas a integram como tal em seus modelos. Isso é um erro, no entanto, porque os valores parabreed
não são compartilhados entre os diferentes valores derace
. Sim, estou ciente de que os outros dois modelos propostos tentam resolver esse problema criandorace
um paibreed
. Embora isso resolva tecnicamente o problema do relacionamento, não ajuda a resolver a questão geral da modelagem sobre o que fazer com propriedades não comuns, nem como lidar com umrace
que não possui umbreed
. Porém, no caso de garantir a existência de tal propriedade em todos osAnimal
s, incluirei uma opção para isso também (abaixo).Animal
), ourace
s sejam armazenadas naAnimal
entidade, que é uma maneira muito simples (e quase não relacional) de representar esses dados. Sim, as pessoas fazem isso o tempo todo, mas isso significa ter muitos campos NULL por linha para as propriedades que não são destinadas a esse determinadorace
AND sabendo quais campos por linha estão associados ao particularrace
desse registro.race
deAnimal
no futuro que não tembreed
como uma propriedade. E mesmo que TODOS osAnimal
s tenham umbreed
, isso não mudaria a estrutura devido ao que foi observado anteriormentebreed
: issobreed
depende dorace
(isto é,breed
paraCat
não é a mesma coisa quebreed
paraDog
)."Raça" como abordagem de propriedade comum / compartilhada
Observe:
O SQL abaixo pode ser executado no mesmo banco de dados que o modelo apresentado acima:
Race
tabela é a mesmaBreed
tabela é novaAnimal
tabelas foram anexadas com um2
Breed
sendo uma propriedade agora comum, não parece certo não terRace
notado na entidade principal / principal (mesmo que tecnicamente seja relacionalmente correta). Então, ambosRaceID
eBreedID
são representados emAnimal2
. Para evitar uma incompatibilidade entre oRaceID
observado emAnimal2
e oBreedID
que é diferenteRaceID
, adicionei um FK em ambos osRaceID, BreedID
que referencia uma RESTRIÇÃO ÚNICA desses campos naBreed
tabela. Eu geralmente desprezo apontar um FK para uma restrição exclusiva, mas aqui está uma das poucas razões válidas para fazer isso. Uma restrição exclusiva é logicamente uma "chave alternativa", que a torna válida para esse uso. Observe também que aBreed
tabela ainda possui um PK apenasBreedID
.BreedID
fosse repetido entre diferentes valores deRaceID
.BreedID
, portanto ainda deve ser possível fazer referência a um valor específicoBreed
sem ter oRaceID
disponível.Breed
(e é por isso que eu prefiro as tabelasRace
específicasBreed
).Breed
têm as mesmas propriedades. Não há uma maneira fácil neste modelo de ter propriedades díspares entreDog
"raças" eElephant
"raças". No entanto, ainda existe uma maneira de fazer isso, que é anotado na seção "Edição final".Breed
em mais de uma corrida. Não tenho certeza se isso é desejável (ou talvez não no conceito de animais, mas possivelmente em outras situações que estariam usando esse tipo de modelo), mas não é possível aqui.Edição final (espero ;-)
Breed
, é possível empregar o mesmo conceito de subclasse / herança, mas comBreed
a entidade principal. Nesta configuração, aBreed
tabela teria as propriedades comuns a todos os tipos deBreed
(assim como aAnimal
tabela) eRaceID
representaria o tipo deBreed
(o mesmo que naAnimal
tabela). Então você teria tabelas subclasses, tais comoBreedCat
,BreedDog
e assim por diante. Para projetos menores, isso pode ser considerado "excesso de engenharia", mas está sendo mencionado como uma opção para situações que se beneficiariam com isso.Para ambas as abordagens, às vezes ajuda a criar Views como atalhos para as entidades completas. Por exemplo, considere:
CreatedDate
campo seria adicionado àAnimal
tabela. Este campo não é necessário em nenhuma das tabelas de subclasse (por exemploAnimalCat
), pois as linhas que estão sendo inseridas nas duas tabelas devem ser executadas ao mesmo tempo em uma transação.LastModifiedDate
campo seria adicionado àAnimal
tabela e a todas as tabelas de subclasse. Este campo é atualizado apenas se essa tabela específica for atualizada: se uma atualização ocorrer,AnimalCat
mas não dentroAnimal
de uma determinadaAnimalID
, somente oLastModifiedDate
campoAnimalCat
será definido.fonte
D
, portanto, queria aplicar o método a partir da sua resposta. Duas entidades têm atributo comumE
que não está presente na terceira entidade. Devo ignorar esse fato e aplicar a solução padrão, ou existe uma maneira de otimizar ainda mais meu design?Primeiro, você está indo bem ao distinguir entre modelagem de ER e modelagem relacional. Muitos novatos não.
Aqui estão algumas palavras-chave que você pode usar para procurar artigos úteis na web.
Seu caso é um caso clássico de classe / subclasse ou, se você preferir, tipo / subtipo.
A frase usada na modelagem de ER é "generalização / especialização". E muitos dos artigos mostram isso em algo chamado modelagem EER (Enhanced Entity-Relationship). Isso não estava na apresentação original de Peter Chen sobre modelagem de ER. Foi adicionado mais tarde. Para um bom resumo de gen / spec em formato pdf, clique aqui
Em seguida, ao converter um caso de classe / subclasse em modelagem relacional, você cria tabelas. Há mais de uma abordagem. As duas abordagens principais são chamadas herança de tabela única e herança de tabela de classe. Cada um tem vantagens e desvantagens. A melhor apresentação desses dois modelos vem de Martin Fowler. Você pode ver o esboço dele aqui e aqui .
A grande vantagem da herança de tabela única é a simplicidade. Está tudo armazenado em uma tabela. A grande desvantagem é um monte de NULLS. Isso pode desperdiçar espaço e tempo e resultar em lógica confusa.
A herança de tabela de classe requer junções, mas elas são simples e rápidas. Especialmente se você usar uma técnica chamada chave primária compartilhada, na qual a PK nas tabelas de subclasse é uma cópia da PK na tabela de superclasse. Você pode criar visualizações para cada subclasse que une dados da superclasse com dados da subclasse.
Por fim, existe uma tag nessa área que coleta perguntas como a sua.
Aqui está: subtipos
fonte
Eu vejo no design possível como
Mesa
Race
Mesa
Breed
Mesa
Animal
Essas PKs acima seriam uma coluna de incremento automático. Outras colunas na
Animal
tabela podem ser nomeadas de acordo.fonte
Seu método atual não é ruim. No entanto, se você quiser adicionar mais corridas mais tarde (pássaro, peixe etc.), criar uma tabela separada para cada uma delas pode ser complicado. Eu recomendaria algo como o seguinte:
Uma raça, no meu entender, deveria ter apenas uma raça. Portanto, se você armazenar a raça na tabela Animal, poderá determinar a raça entrando na tabela Breed. Obviamente, adicione outros atributos (nome, descrição, etc.) às tabelas de raça e raça, conforme necessário.
fonte