Pergunta

Suponha que você configurar um banco de dados para armazenar dados de testes de colisão de vários veículos. Você deseja armazenar os dados de testes de colisão para lanchas, carros, e go-karts.

Você pode criar três mesas separadas: SpeedboatTests, CarTests e GokartTests. Mas um monte de suas colunas vão ser o mesmo em cada tabela (por exemplo, a identificação do empregado da pessoa que realizou o teste, a direção da colisão (frontal, lateral, traseira), etc.). No entanto, a abundância de colunas será diferente, para que você não quer apenas colocar todos os dados de teste em uma única tabela porque você vai ter algumas colunas que serão sempre nulo para lanchas, muito poucos que será sempre ser nulo para carros, e muito poucos que sempre será nulo para karts.

Vamos dizer que você também deseja armazenar algumas informações que não está directamente relacionado com os testes (como a identificação do funcionário do designer da coisa que está sendo testado). Estas colunas não parece certo para colocar em uma mesa de "testes" em tudo, especialmente porque eles vão ser repetido para todos os testes, no mesmo veículo.

Deixe-me ilustrar um possível arranjo de mesas, para que possa ver as questões envolvidas.

Speedboats
id | col_about_speedboats_but_not_tests1 | col_about_speedboats_but_not_tests2

Cars
id | col_about_cars_but_not_tests1 | col_about_cars_but_not_tests2

Gokarts
id | col_about_gokarts_but_not_tests1 | col_about_gokarts_but_not_tests2

Tests
id | type | id_in_type | col_about_all_tests1 | col_about_all_tests2
(id_in_type will refer to the id column of one of the next three tables,
depending on the value of type)

SpeedboatTests
id | speedboat_id | col_about_speedboat_tests1 | col_about_speedboat_tests2

CarTests
id | car_id | col_about_car_tests1 | col_about_car_tests2

GokartTests
id | gokart_id | col_about_gokart_tests1 | col_about_gokart_tests2

O que é bom / mau sobre esta estrutura e qual seria a melhor maneira de implementar algo parecido com isto?

E se há também algumas informações que se aplica a todos os veículos que você preferiria ter em uma tabela de Veículos? Será que a mesa de CarTests então algo parecido ...

id | vehicle_id | ...

With a Vehicles table like this:
id | type | id_in_type
(with id_in_type pointing to the id of either a speedboat, car, or go-kart)

Este é apenas começando a ser uma bagunça real parece. Como deve ser algo como isto ser configurado?

Foi útil?

Solução

O projeto type e id_in_type é chamado associações polimórficas . Este projeto rompe regras de normalização de várias maneiras. Se nada mais, ele deve ser uma bandeira vermelha que você não pode declarar uma verdadeira restrição de chave estrangeira, porque o id_in_type pode fazer referência a qualquer uma das várias tabelas.

Aqui está uma maneira melhor de definir suas tabelas:

  • Faça uma tabela Vehicles abstrato para fornecer um ponto de referência abstrata para todos os veículos sub-tipos e testes de veículos.
  • Cada veículo sub-tipo tem uma chave primária que não auto-incremento, mas em vez disso referências Vehicles.
  • Cada teste sub-tipo tem uma chave primária que não auto-incremento, mas em vez disso referências Tests.
  • Cada teste sub-tipo também possui uma chave estrangeira para o sub-tipo de veículo correspondente.

Aqui está DDL de exemplo:

CREATE TABLE Vehicles (
 vehicle_id INT AUTO_INCREMENT PRIMARY KEY
);

CREATE TABLE Speedboats (
 vehicle_id INT PRIMARY KEY,
 col_about_speedboats_but_not_tests1 INT,
 col_about_speedboats_but_not_tests2 INT,
 FOREIGN KEY(vehicle_id) REFERENCES Vehicles(vehicle_id)
);

CREATE TABLE Cars (
 vehicle_id INT PRIMARY KEY,
 col_about_cars_but_not_tests1 INT,
 col_about_cars_but_not_tests2 INT,
 FOREIGN KEY(vehicle_id) REFERENCES Vehicles(vehicle_id)
);

CREATE TABLE Gokarts (
 vehicle_id INT PRIMARY KEY,
 col_about_gokarts_but_not_tests1 INT,
 col_about_gokarts_but_not_tests2 INT,
 FOREIGN KEY(vehicle_id) REFERENCES Vehicles(vehicle_id)
);

CREATE TABLE Tests (
 test_id INT AUTO_INCREMENT PRIMARY KEY,
 col_about_all_tests1 INT,
 col_about_all_tests2 INT
);

CREATE TABLE SpeedboatTests (
 test_id INT PRIMARY KEY,
 vehicle_id INT NOT NULL,
 col_about_speedboat_tests1 INT,
 col_about_speedboat_tests2 INT,
 FOREIGN KEY(test_id) REFERENCES Tests(test_id),
 FOREIGN KEY(vehicle_id) REFERENCES Speedboats(vehicle_id)
);

CREATE TABLE CarTests (
 test_id INT PRIMARY KEY,
 vehicle_id INT NOT NULL,
 col_about_car_tests1 INT,
 col_about_car_tests2 INT,
 FOREIGN KEY(test_id) REFERENCES Tests(test_id),
 FOREIGN KEY(vehicle_id) REFERENCES Cars(vehicle_id)
);

CREATE TABLE GokartTests (
 test_id INT PRIMARY KEY,
 vehicle_id INT NOT NULL,
 col_about_gokart_tests1 INT,
 col_about_gokart_tests2 INT,
 FOREIGN KEY(test_id) REFERENCES Tests(test_id),
 FOREIGN KEY(vehicle_id) REFERENCES Gokarts(vehicle_id)
);

Você pode, alternativamente, declarar Tests.vehicle_id que referências Vehicles.vehicle_id e livrar-se das chaves estrangeiras vehicle_id em cada tabela de teste sub-tipo, mas que permitiria anomalias, tais como um teste lancha que as referências id de um gokart.

Outras dicas

Para hierarquias de herança mapeamento para tabelas de banco de dados, eu acho que Martin Fowler estabelece as alternativas razoavelmente bem em seus padrões contábeis de arquitetura de aplicações corporativas.

http://martinfowler.com/eaaCatalog/singleTableInheritance.html

http://martinfowler.com/eaaCatalog/classTableInheritance.html

http://martinfowler.com/eaaCatalog/concreteTableInheritance.html

Se o número de campos / colunas adicionais é pequeno para subclasses, então herança única tabela é geralmente o mais simples de lidar com eles.

Se você estiver usando PostgreSQL para o seu banco de dados e você está disposto a amarrar-se a uma característica específica do banco de dados, ele suporta herança tabela diretamente:

http://www.postgresql.org/docs/8.3/ static / ddl-inherit.html

Gostaria de dividi-lo em diferentes tabelas, por exemplo, Veículo (ID, tipo, etc.) VehicleAttributes () VehicleID, attributeID, Value), CrashTestInfo (VehicleID, CrashtestID, data etc.) CrashtestAttributes (CrashTestID, attributeID, Valor)

Ou, em vez de atributos, tabelas separadas para cada conjunto de detalhes semelhantes que devem ser registrados.

Se você estiver usando SQLAlchemy , um mapeador objeto-relacional para Python, você pode configure como hierarquias de herança são mapeados para tabelas de banco de dados . mapeadores objeto-relacional são bons para domar SQL outra forma tedioso.

Seu problema pode ser um bom ajuste para tabelas verticais. Em vez de armazenar tudo no esquema, armazenar o tipo do objeto e chave primária em uma tabela e uma chave / valor tuplas para cada objeto em outra tabela. Se você realmente estavam armazenando ensaios de automóveis, esta configuração tornaria muito mais fácil adicionar novos tipos de resultados.

Faça uma pesquisa no Google sobre "modelagem relacional gen-spec". Você vai encontrar artigos sobre como configurar tabelas que armazenam os atributos da entidade generalizada (o que os programadores OO pode chamar a superclasse), mesas separadas para cada uma das entidades especializadas (subclasses), e como usar chaves estrangeiras para vinculá-lo todos juntos.

Os melhores artigos, IMO, discutir gen-spec em termos de modelagem ER. Se você sabe como traduzir um modelo ER em um modelo relacional, e daí para tabelas SQL, você vai saber o que fazer quando eles mostram-lhe como modelar gen-spec em ER.

Se você apenas google em "gen-spec", mais do que você vai ver é orientada a objetos, não relacional orientado. Esse material pode ser útil como bem, desde que você sabe como superar o objeto relacional diferença de impedância.

Seu projeto é razoável e está seguindo as regras de normalização corretas. Você pode estar faltando uma mesa de veículos com uma identificação do veículo e tipo (ou seja, o "pai" para lanchas, carros, e Gokarts ... onde você iria manter o material como "DesignedByUserId"). Entre a tabela de veículo e a tabela de lanchas é um um - de - um relacionamento, e entre o veículo e da lancha / Carros / gokarts existe um e apenas 1 1-relação (isto é, um veículo pode ter apenas uma ficha para a lancha,. carros ou karts) ... embora a maioria do db não oferecem um mecanismo de aplicação fácil para isso.

Uma regra de normalização que ajuda a identificar esses tipos de coisas é que um campo deve depender apenas da chave primária da tabela. Em um quadro consolidado, onde lancha, carros e gokart resultados dos testes são armazenados juntos, em seguida, os carros campos relacionados dependem não só a data do teste, mas também sobre o tipo id vechicle e do veículo. A chave primária para a tabela de resultados do teste é data do teste id + veículo e tipo de veículo não é o que faz a linha de dados único teste (ie há de qualquer maneira para realizar um teste sobre 01/01/200912:. 30pm em um veículo específico que é tanto uma lancha e carro ... Nope ... não pode ser feito).

Eu não estou explicando a regra de normalização particularily bem ... mas 3º / 4º / 5º regras formas normais sempre me confunde quando li as descrições formais. Uma delas (3º / 4º / 5º) lida com campos, dependendo da chave primária e somente a chave primária. A regra fazer a suposição de que a chave primária foi corretamente identificada (incorretamente defininh a chave primária é muito fácil de fazer).

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top