Não sei como transformar entidade variável em tabela relacional


9

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:

insira a descrição da imagem aqui

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.


11
A transformação dos diagramas de EER em tabelas pode ser encontrada neste artigo de 1986 de TJTeorey, D.Yang, JPFry: uma metodologia de design lógico para bancos de dados relacionais usando o modelo estendido de relacionamento entre entidades . É simples e um dos meus papéis favoritos.
miracle173

Respostas:


11

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 Animalentidade contém o tipo (ou seja race) e as propriedades comuns a todos os tipos. No entanto, existem duas pequenas alterações necessárias:

  1. Remova os campos Cat_ID e Dog_ID de suas respectivas entidades:

    O conceito chave aqui é que tudo é um Animal, independentemente race: Cat, Dog, Elephant, e assim por diante. Dado que o ponto de partida, qualquer particular, racede Animalnão realmente precisa de um identificador separado desde:

    1. o Animal_IDé único
    2. o Cat,, Doge quaisquer raceentidades adicionais adicionadas no futuro, por si só, não representam totalmente nenhum detalhe Animal; apenas têm significado quando utilizados em combinação com as informações contidas na entidade - mãe Animal.

    Assim, a Animal_IDpropriedade no Cat, Dog, etc entidades é tanto o PK e as costas FK à Animalentidade.

  2. 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 CatBreede DogBreedcomo "tipos" separados

Notas iniciais

  1. O SQL é específico para o Microsoft SQL Server (ou seja, é T-SQL). Ou seja, tenha cuidado com os tipos de dados, pois eles não são os mesmos em todos os RDBMSs. Por exemplo, estou usando, VARCHARmas se você precisar armazenar algo fora do conjunto ASCII padrão, você deve realmente usá-lo NVARCHAR.
  2. Os campos de identificação das mesas "tipo" ( Race, CatBreede DogBreed) 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 como enums 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.
  3. A convenção de nomenclatura que eu uso é nomear cada tabela de subclasse começando com o nome da classe principal seguido pelo nome da subclasse. Isso ajuda a organizar as tabelas e indica claramente (sem olhar para os FKs) o relacionamento da tabela da subclasse com a tabela principal da entidade.
  4. Consulte a seção "Edição final" no final para obter uma observação sobre as visualizações.

"Raça" como abordagem específica de "raça"

Raça como diagrama específico da raça
Este primeiro conjunto de tabelas são as tabelas de pesquisa / tipos:

CREATE TABLE Race
(
  RaceID INT NOT NULL PRIMARY KEY
  RaceName VARCHAR(50) NOT NULL
);

CREATE TABLE CatBreed
(
  CatBreedID INT NOT NULL PRIMARY KEY,
  BreedName VARCHAR(50),
  CatBreedAttribute1 INT,
  CatBreedAttribute2 VARCHAR(10)
  -- other "CatBreed"-specific properties as needed
);

CREATE TABLE DogBreed
(
  DogBreedID INT NOT NULL PRIMARY KEY,
  BreedName VARCHAR(50),
  DogBreedAttribute1 TINYINT
  -- other "DogBreed"-specific properties as needed
);

Esta segunda listagem é a principal entidade "Animal":

CREATE TABLE Animal
(
  AnimalID INT NOT NULL IDENTITY(1, 1) PRIMARY KEY,
  RaceID INT NOT NULL, -- FK to Race
  Name VARCHAR(50)
  -- other "Animal" properties that are shared across "Race" types
);

ALTER TABLE Animal
  ADD CONSTRAINT [FK_Animal_Race]
  FOREIGN KEY (RaceID)
  REFERENCES Race (RaceID);

Este terceiro conjunto de tabelas são as entidades de subclasse complementares que completam a definição de cada um Racedos seguintes Animal:

CREATE TABLE AnimalCat
(
  AnimalID INT NOT NULL PRIMARY KEY, -- FK to Animal
  CatBreedID INT NOT NULL, -- FK to CatBreed
  HairColor VARCHAR(50) NOT NULL
  -- other "Cat"-specific properties as needed
);

ALTER TABLE AnimalCat
  ADD CONSTRAINT [FK_AnimalCat_CatBreed]
  FOREIGN KEY (CatBreedID)
  REFERENCES CatBreed (CatBreedID);

ALTER TABLE AnimalCat
  ADD CONSTRAINT [FK_AnimalCat_Animal]
  FOREIGN KEY (AnimalID)
  REFERENCES Animal (AnimalID);


CREATE TABLE AnimalDog
(
  AnimalID INT NOT NULL PRIMARY KEY, -- FK to Animal
  DogBreedID INT NOT NULL, -- FK to DogBreed
  HairColor VARCHAR(50) NOT NULL
  -- other "Dog"-specific properties as needed
);

ALTER TABLE AnimalDog
  ADD CONSTRAINT [FK_AnimalDog_DogBreed]
  FOREIGN KEY (DogBreedID)
  REFERENCES DogBreed (DogBreedID);

ALTER TABLE AnimalDog
  ADD CONSTRAINT [FK_AnimalDog_Animal]
  FOREIGN KEY (AnimalID)
  REFERENCES Animal (AnimalID);

O modelo que usa um breedtipo compartilhado é mostrado após a seção "Notas adicionais".

Notas Adicionais

  1. O conceito de breedparece ser um ponto focal de confusão. Foi sugerido por jcolebrand (em um comentário sobre a pergunta) que breedé uma propriedade compartilhada entre os diferentes races, e as outras duas respostas a integram como tal em seus modelos. Isso é um erro, no entanto, porque os valores para breednão são compartilhados entre os diferentes valores de race. Sim, estou ciente de que os outros dois modelos propostos tentam resolver esse problema criando raceum pai breed. 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 um raceque não possui um breed. Porém, no caso de garantir a existência de tal propriedade em todos osAnimals, incluirei uma opção para isso também (abaixo).
  2. Os modelos propostos por vijayp e DavidN (que parecem idênticos) não funcionam porque:
    1. Eles também
      1. não permita que propriedades não comuns sejam armazenadas (pelo menos não para instâncias individuais de nenhuma Animal), ou
      2. exigem que todas as propriedades para todos os races sejam armazenadas na Animalentidade, 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 determinado raceAND sabendo quais campos por linha estão associados ao particular racedesse registro.
    2. Eles não permitem adicionar um racede Animalno futuro que não tem breedcomo uma propriedade. E mesmo que TODOS os Animals tenham um breed, isso não mudaria a estrutura devido ao que foi observado anteriormente breed: isso breeddepende do race(isto é, breedpara Catnão é a mesma coisa que breedpara Dog).

"Raça" como abordagem de propriedade comum / compartilhada

insira a descrição da imagem aqui
Observe:

  1. O SQL abaixo pode ser executado no mesmo banco de dados que o modelo apresentado acima:

    1. A Racetabela é a mesma
    2. A Breedtabela é nova
    3. As três Animaltabelas foram anexadas com um2
  2. Mesmo Breedsendo uma propriedade agora comum, não parece certo não ter Racenotado na entidade principal / principal (mesmo que tecnicamente seja relacionalmente correta). Então, ambos RaceIDe BreedIDsão representados em Animal2. Para evitar uma incompatibilidade entre o RaceIDobservado em Animal2e o BreedIDque é diferente RaceID, adicionei um FK em ambos os RaceID, BreedIDque referencia uma RESTRIÇÃO ÚNICA desses campos na Breedtabela. 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 a Breedtabela ainda possui um PK apenas BreedID.
    1. O motivo para não usar apenas uma PK nos campos combinados e nenhuma restrição UNIQUE é que permitiria que o mesmo BreedIDfosse repetido entre diferentes valores de RaceID.
    2. O motivo para não alternar entre o PK e o UNIQUE CONSTRAINT é que esse pode não ser o único uso BreedID, portanto ainda deve ser possível fazer referência a um valor específico Breedsem ter o RaceIDdisponível.
  3. Embora o modelo a seguir funcione, ele tem duas falhas em potencial em relação ao conceito de um compartilhamento Breed(e é por isso que eu prefiro as tabelas Raceespecíficas Breed).
    1. Há uma suposição implícita de que TODOS os valores Breedtêm as mesmas propriedades. Não há uma maneira fácil neste modelo de ter propriedades díspares entre Dog"raças" e Elephant"raças". No entanto, ainda existe uma maneira de fazer isso, que é anotado na seção "Edição final".
    2. Não há como compartilhar uma Breedem 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.
CREATE TABLE Race
(
  RaceID INT NOT NULL PRIMARY KEY,
  RaceName VARCHAR(50) NOT NULL
);

CREATE TABLE Breed
(
  BreedID INT NOT NULL PRIMARY KEY,
  RaceID INT NOT NULL, -- FK to Race
  BreedName VARCHAR(50)
);

ALTER TABLE Breed
  ADD CONSTRAINT [UQ_Breed]
  UNIQUE (RaceID, BreedID);

ALTER TABLE Breed
  ADD CONSTRAINT [FK_Breed_Race]
  FOREIGN KEY (RaceID)
  REFERENCES Race (RaceID);

CREATE TABLE Animal2
(
  AnimalID INT NOT NULL IDENTITY(1, 1) PRIMARY KEY,
  RaceID INT NOT NULL, -- FK to Race, FK to Breed
  BreedID INT NOT NULL, -- FK to Breed
  Name VARCHAR(50)
  -- other properties common to all "Animal" types
);

ALTER TABLE Animal2
  ADD CONSTRAINT [FK_Animal2_Race]
  FOREIGN KEY (RaceID)
  REFERENCES Race (RaceID);

-- This FK points to the UNIQUE CONSTRAINT on Breed, _not_ to the PK!
ALTER TABLE Animal2
  ADD CONSTRAINT [FK_Animal2_Breed]
  FOREIGN KEY (RaceID, BreedID)
  REFERENCES Breed (RaceID, BreedID);


CREATE TABLE AnimalCat2
(
  AnimalID INT NOT NULL PRIMARY KEY, -- FK to Animal
  HairColor VARCHAR(50) NOT NULL
);

ALTER TABLE AnimalCat2
  ADD CONSTRAINT [FK_AnimalCat2_Animal2]
  FOREIGN KEY (AnimalID)
  REFERENCES Animal2 (AnimalID);

CREATE TABLE AnimalDog2
(
  AnimalID INT NOT NULL PRIMARY KEY,
  HairColor VARCHAR(50) NOT NULL
);

ALTER TABLE AnimalDog2
  ADD CONSTRAINT [FK_AnimalDog2_Animal2]
  FOREIGN KEY (AnimalID)
  REFERENCES Animal2 (AnimalID);


Edição final (espero ;-)

  1. Com relação à possibilidade (e depois à dificuldade) de lidar com propriedades díspares entre tipos de Breed, é possível empregar o mesmo conceito de subclasse / herança, mas com Breeda entidade principal. Nesta configuração, a Breedtabela teria as propriedades comuns a todos os tipos de Breed(assim como a Animaltabela) e RaceIDrepresentaria o tipo de Breed(o mesmo que na Animaltabela). Então você teria tabelas subclasses, tais como BreedCat, BreedDoge 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.
  2. Para ambas as abordagens, às vezes ajuda a criar Views como atalhos para as entidades completas. Por exemplo, considere:

    CREATE VIEW Cats AS
       SELECT  an.AnimalID,
               an.RaceID,
               an.Name,
               -- other "Animal" properties that are shared across "Race" types
               cat.CatBreedID,
               cat.HairColor
               -- other "Cat"-specific properties as needed
       FROM    Animal an
       INNER JOIN  AnimalCat cat
               ON  cat.AnimalID = an.AnimalID
       -- maybe add in JOIN(s) and field(s) for "Race" and/or "Breed"
  3. Embora não faça parte das entidades lógicas, é bastante comum ter campos de auditoria nas tabelas para ter uma noção de quando os registros estão sendo inseridos e atualizados. Então, em termos práticos:
    1. Um CreatedDatecampo seria adicionado à Animaltabela. Este campo não é necessário em nenhuma das tabelas de subclasse (por exemplo AnimalCat), pois as linhas que estão sendo inseridas nas duas tabelas devem ser executadas ao mesmo tempo em uma transação.
    2. Um LastModifiedDatecampo seria adicionado à Animaltabela e a todas as tabelas de subclasse. Este campo é atualizado apenas se essa tabela específica for atualizada: se uma atualização ocorrer, AnimalCatmas não dentro Animalde uma determinada AnimalID, somente o LastModifiedDatecampo AnimalCatserá definido.

2
De alguma forma, sinto que você entendeu exatamente qual é o meu problema. Vou dar uma olhada na sua resposta vinculada e estudá-la cuidadosamente. Apenas uma definição simples de tabelas também seria ótima (se as consultas SQL forem demais para você escrever no momento). Se você decidir atualizar sua postagem com consultas SQL ou definições de tabela, deixe-me um comentário. Mais uma vez obrigado. Cumprimentos.
AlwaysLearningNewStuff

11
Estou tentando aplicar sua resposta ao meu caso da vida real. Se eu seguir cegamente suas instruções, acredito que posso perder a oportunidade de otimizar ainda mais meu design. Gostaria que você desse uma olhada na minha pergunta mais recente, pois conseguiu entender perfeitamente minhas perguntas e fornecer excelentes respostas. Compus a pergunta para usar o modelo de dados genéricos para ser útil também para futuros leitores. Se você tiver problemas para encontrá-lo, deixe-me um comentário. Obrigado e desculpe por perturbar ...
AlwaysLearningNewStuff

@AlwaysLearningNewStuff Olá. Recebi esta mensagem mais cedo, mas não tive tempo de recebê-la imediatamente. Consegui encontrar a nova pergunta clicando no seu nome acima e ela mostra todas as suas perguntas :-).
Solomon Rutzky,

Eu estava me referindo a esta pergunta . Em poucas palavras: tenho 3 entidades com atributo comum D, portanto, queria aplicar o método a partir da sua resposta. Duas entidades têm atributo comum Eque 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?
AlwaysLearningNewStuff 7/16

4

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á:


11
+1 O que me confunde é a falta de chaves primárias nos diagramas de tabela. Especialmente em "classTableInheritance", não consigo ver que todas essas tabelas estão conectadas pela mesma chave primária.
miracle173

@ miracle173 um ponto válido. Por alguma razão, Fowler não inclui os PKs e FKs no diagrama. Existem outros artigos na herança da tabela de classes que fornecem esse detalhe. Nem todas as implementações da herança da tabela de classes a combinam com a chave primária compartilhada. Eu recomendo. É um pouco mais trabalhoso no momento da inserção, mas mais fácil e rápido no momento da recuperação combinada.
Walter Mitty

3

Eu vejo no design possível como

Mesa Race

RaceId- PK- Int
RaceName - Varchar(50)

Mesa Breed

BreedId - PK- Int
RaceId - FK - Int
BreedName - varchar(50)

Mesa Animal

AnimalId - PK- Int
BreedId - FK - Int
Other Columns....

Essas PKs acima seriam uma coluna de incremento automático. Outras colunas na Animaltabela podem ser nomeadas de acordo.

insira a descrição da imagem aqui


Além disso, eu adicionaria um campo com as teclas Raça e Tipo (poderiam ser gatilhos) na tabela Animal, a fim de facilitar índices posteriores para melhorar a velocidade.
Felipe Alcacibar 27/10

0

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:

Animal < # Animal_ID, Breed_ID, other attributes >
Breed < # Breed_ID, Race_ID >
Race < # Race_ID >

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.

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.