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 labrador retriver .
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 um monte de outras coisas).
PROBLEMA:
Não sei como criar tabelas relacionais para este exemplo.
MEUS ESFORÇOS PARA RESOLVER O PROBLEMA:
Tentei desenhar o diagrama ER, usando a notação de Chen, que representa o problema, mas sendo iniciante não sei se fiz certo. Aqui está o que eu tenho:
Peço desculpas se desenhei algo errado, por favor me corrija se for o caso. Não desejo simplesmente obter "solução gratuita", mas também aprender como lidar com esse problema para que eu possa resolvê-lo sozinho no futuro.
A única coisa que me vem à cabeça é criar duas mesas separadas, uma para gatos e outra para cachorros. Além disso, o atributo raça na tabela Animal armazenaria apenas um 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 errada, daí a pergunta abaixo.
PERGUNTAS:
- Como posso transformar meu exemplo em diagrama ER?
- Como transformar esse diagrama 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 relativamente novo aqui.
Obrigada.
A estrutura adequada para este cenário é um modelo de subclasse/herança e é quase idêntica ao conceito que propus nesta resposta: lista ordenada heterogênea de valores .
O modelo proposto nesta questão é, na verdade, bastante próximo, pois a
Animal
entidade contém o tipo (ou seja,race
) e as propriedades comuns a todos os tipos. No entanto, há duas pequenas alterações que são necessárias:Remova os campos Cat_ID e Dog_ID de suas respectivas entidades:
O conceito-chave aqui é que tudo é um
Animal
, independentemente derace
:Cat
,Dog
,Elephant
e assim por diante. Dado esse ponto de partida, qualquer particular não precisa realmente de um identificador separado, poisrace
:Animal
Animal_ID
é únicoCat
,Dog
, e quaisquerrace
entidades adicionais adicionadas no futuro não representam, por si só, totalmente qualquerAnimal
; eles só têm significado quando usados em combinação com as informações contidas na entidade-mãe,Animal
.Portanto, a
Animal_ID
propriedade nas entidadesCat
,Dog
, etc é a PK e a FK de volta àAnimal
entidade.Diferencie os tipos de
breed
:Só porque duas propriedades compartilham o mesmo nome não significa necessariamente que essas propriedades são as mesmas, mesmo que o nome seja o mesmo implique tal relacionamento.
CatBreed
Neste caso, o que você realmente tem sãoDogBreed
"tipos" separadosNotas Iniciais
VARCHAR
mas se você precisar armazenar qualquer coisa fora do conjunto ASCII padrão, você realmente deve usarNVARCHAR
.Race
,CatBreed
, eDogBreed
) não são incrementados automaticamente (ou seja, IDENTITY em termos de T-SQL) porque são constantes do aplicativo (ou seja, fazem parte do aplicativo) que são valores de pesquisa estáticos no banco de dados e são representados comoenum
s em C# (ou outras linguagens). Se valores forem adicionados, eles serão adicionados em situações controladas. Eu reservo o uso de campos de auto-incremento para dados do usuário que chegam através do aplicativo."Raça" como "Raça" - Abordagem Específica
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 uma
Race
das seguintesAnimal
:O modelo que usa um tipo compartilhado
breed
é mostrado após a seção "Notas adicionais".Notas Adicionais
breed
parece ser um ponto focal para 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 debreed
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 pai debreed
. Embora isso resolva tecnicamente o problema de relacionamento, não ajuda a resolver a questão geral de modelagem sobre o que fazer com propriedades não comuns, nem como lidar com umrace
que não possui umbreed
. Mas, no caso de tal propriedade ter a garantia de existir em todos osAnimal
s, incluirei uma opção para isso também (abaixo).Animal
), ourace
s sejam armazenadas naAnimal
entidade, que é uma maneira muito plana (e quase não relacional) de representar esses dados. Sim, as pessoas fazem isso o tempo todo, mas significa ter muitos campos NULL por linha para as propriedades que não são destinadas a esse determinadorace
E saber quais campos por linha estão associados ao particularrace
desse registro.race
ofAnimal
no futuro que não tenhabreed
como propriedade. E mesmo que ALLAnimal
s tenha umbreed
, isso não mudaria a estrutura devido ao que foi observado anteriormentebreed
: issobreed
depende de therace
(ou seja,breed
forCat
não é a mesma coisa quebreed
forDog
)."Raça" como abordagem de propriedade comum/compartilhada
Observe:
O SQL abaixo pode ser executado no mesmo banco de dados do modelo apresentado acima:
Race
mesa é a mesmaBreed
mesa é novaAnimal
tabelas foram anexadas com um2
Breed
being a now common property, it does not seem right not to haveRace
noted in the main/parent entity (even if it is technically relationally correct). So, bothRaceID
andBreedID
are represented inAnimal2
. In order to prevent a mismatch between theRaceID
noted inAnimal2
and aBreedID
that is for a differentRaceID
, I have added a FK on bothRaceID, BreedID
that references a UNIQUE CONSTRAINT of those fields in theBreed
table. I usually despise pointing a FK to a UNIQUE CONSTRAINT, but here is one of the few valid reasons to do so. A UNIQUE CONSTRAINT is logically an "Alternate Key", which makes it valid for this use. Please also note that theBreed
table still has a PK on justBreedID
.BreedID
to be repeated across different values ofRaceID
.BreedID
, so it should still be possible to reference a specific value ofBreed
without having theRaceID
available.Breed
(and are why I prefer theRace
-specificBreed
tables).Breed
have the same properties. There is no easy way in this model to have disparate properties betweenDog
"breeds" andElephant
"breeds". However, there still is a way to do this, which is noted in the "Final Edit" section.Breed
across more than one race. I am not sure if that is desirable to do (or maybe not in the concept of animals but possibly in other situations that would be using this type of model), but it is not possible here.Final Edit (hopefully ;-)
Breed
, it is possible to employ the same subclass / inheritance concept but withBreed
as the main entity. In this setup theBreed
table would have the properties common to all types ofBreed
(just like theAnimal
table) andRaceID
would represent the type ofBreed
(same as it does in theAnimal
table). Then you would have subclass tables such asBreedCat
,BreedDog
, and so on. For smaller projects this might be considered "over-engineering", but it is being mentioned as an option for situations that would benefit from it.For both approaches, it sometimes helps to create Views as short-cuts to the full entities. For example, consider:
CreatedDate
field would be added to theAnimal
table. This field is not needed in any of the subclass tables (e.g.AnimalCat
) as the rows being inserted for both tables should be done at the same time within a transaction.LastModifiedDate
field would be added to theAnimal
table and all subclass tables. This field gets updated only if that particular table is updated: if an update occurs inAnimalCat
but not inAnimal
for a particularAnimalID
, then only theLastModifiedDate
field inAnimalCat
would be set.First off, you are doing well to distinguish between ER modeling and relational modeling. Many newbies don't.
Here are some buzzwords you can use to look up helpful articles on the web.
Your case is a classic case of class/subclass or, if you like, type/subtype.
The phrase that's used in ER modeling is "generalization/specialization". And many of the articles show this under something called EER (Enhanced Entity-Relationship) modeling. This wasn't in Peter Chen's original presentation of ER modeling. It was added later. For a pretty good summary of gen/spec in pdf form, click here
Next, when converting a class/subclass case to relational modeling you design tables. There is more than one approach. The two main approaches are called single table inheritance and class table inheritance. Each has advantages and drawbacks. The best presentation of these two designs comes from Martin Fowler. You can see his outline here and here.
The big advantage of single table inheritance is simplicity. It's all stored in one table. The big drawback is a lot of NULLS. This can waste space and time and result in confusing logic.
A herança da tabela de classes 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 o PK nas tabelas da subclasse é uma cópia do PK na tabela da superclasse. Você pode criar exibições para cada subclasse que une dados de superclasse com dados de subclasse.
Finalmente, há uma tag nesta área que reúne perguntas como a sua.
Aqui está: subtipos
Eu vejo no design possível como
Mesa
Race
Mesa
Breed
Mesa
Animal
Esses PKs acima seriam colunas de incremento automático. Outras colunas na
Animal
tabela podem ser nomeadas de acordo.Seu método atual não é ruim. No entanto, se você adicionar mais raças posteriormente (pássaro, peixe, etc.), criar uma tabela separada para cada uma pode ser complicado. Eu recomendaria algo como o seguinte:
Uma raça, no meu entendimento, deveria ter apenas uma raça. Portanto, se você armazenar a raça na tabela Animal, poderá determinar a raça juntando-se à tabela Raça. Obviamente, adicione quaisquer outros atributos (nome, descrição, etc.) às tabelas de raças e raças conforme necessário.