Question

Supposons que vous établissiez une base de données pour stocker des données d'essais de collision de véhicules différents. Vous souhaitez stocker les données des essais de collision pour les voitures, hors-bords, et go-karts.

Vous pouvez créer trois tables distinctes: SpeedboatTests, CarTests et GokartTests. Mais beaucoup de vos colonnes vont être les mêmes dans chaque table (par exemple, l'identifiant d'employé de la personne qui a effectué le test, la direction de la collision (avant, côté, arrière), etc.). Cependant, beaucoup de colonnes sera différent, de sorte que vous ne voulez pas mettre simplement toutes les données de test dans une seule table parce que vous aurez un bon nombre de colonnes qui seront toujours nulle pour hors-bords, bien que quelques-uns qui seront toujours nul pour les voitures, et un certain nombre qui sera toujours nulle pour go-karts.

Disons que vous voulez également stocker des informations qui ne sont pas directement liées aux essais (tels que l'ID d'employé du concepteur de la chose à l'essai). Ces colonnes ne semblent pas le droit de mettre dans une table du tout, en particulier parce qu'ils seront répétées pour « Tests » tous les tests sur le même véhicule.

Permettez-moi d'illustrer un arrangement possible des tables, afin que vous puissiez voir les questions en jeu.

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

Ce qui est bon / mauvais au sujet de cette structure et ce serait le meilleur moyen de mettre en œuvre quelque chose comme ça?

Et s'il y a aussi des informations qui s'applique à tous les véhicules que vous préféreriez avoir dans une table Véhicules? Est-ce que la table CarTests alors ressembler à quelque chose comme ...

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)

Il est juste d'apprendre à être un gâchis royal il semble. Comment DEVRAIT quelque chose comme ça être mis en place?

Était-ce utile?

La solution

La conception de type et id_in_type est appelé . Cette conception enfreint les règles de normalisation de multiples façons. Si rien d'autre, il devrait être un drapeau rouge que vous ne peut pas Déclarez une contrainte réelle clé étrangère, car le id_in_type peut faire référence à l'une des plusieurs tables.

Voici une meilleure façon de définir vos tables:

  • Faire une Vehicles table abstraite pour fournir un point de référence abstraite pour tous les sous-types de véhicules et essais de véhicules.
  • Chaque sous-type de véhicule a une clé primaire qui ne fonctionne pas auto-incrément, mais fait référence à la place Vehicles.
  • Chaque sous-type de test a une clé primaire qui ne fonctionne pas auto-incrément, mais fait référence à la place Tests.
  • Chaque sous-type de test a aussi une clé étrangère au sous-type de véhicule correspondant.

Voici échantillon DDL:

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)
);

Vous pourriez aussi déclarer Tests.vehicle_id qui fait référence Vehicles.vehicle_id et se débarrasser des clés étrangères vehicle_id dans chaque table sous-type de test, mais qui permettrait des anomalies, comme un test de bateau rapide qui fait référence à l'identifiant d'un gokart.

Autres conseils

Pour des hiérarchies d'héritage de mappage des tables de base de données, je pense que Martin Fowler expose les alternatives assez bien dans son livre Les modèles de l'architecture d'entreprise d'application.

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

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

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

Si le nombre de champs / colonnes supplémentaires est faible pour les sous-classes, puis l'héritage de table unique est généralement le plus simple à traiter.

Si vous utilisez PostgreSQL pour votre base de données et vous êtes prêt à vous attacher à une caractéristique spécifique à la base, il prend en charge directement l'héritage de table:

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

Je diviser en différentes tables, par exemple Véhicule (ID, type, etc.) VehicleAttributes () VehicleID, AttributeID, valeur), CrashTestInfo (VehicleID, CrashtestID, date, etc.) CrashtestAttributes (CrashTestID, AttributeID, valeur)

Ou plutôt que des attributs, des tables séparées pour chaque ensemble de détails similaires qui doivent être enregistrées.

Si vous utilisez SQLAlchemy , un mappeur objet-relationnel pour Python, vous pouvez comment configurer les hiérarchies d'héritage sont mis en correspondance avec les tables de base de données . cartographes objet-relationnel sont bonnes pour dompter SQL sinon fastidieux.

Votre problème est peut-être un bon ajustement pour les tables verticales. Au lieu de stocker tout dans le schéma, stocker le type de l'objet et la clé primaire dans une table et tuples clé / valeur pour chaque objet dans une autre table. Si vous étiez vraiment stocker des tests de voiture, cette configuration serait beaucoup plus facile d'ajouter de nouveaux types de résultats.

Faites une recherche google sur "la modélisation relationnelle gen-spec". Vous trouverez des articles sur la façon de mettre en place des tables qui stockent les attributs de l'entité généralisée (ce que les programmeurs OO pourrait appeler la superclasse), des tables distinctes pour chacune des entités spécialisées (sous-classes), et comment utiliser les clés étrangères pour relier tous ensemble.

Les meilleurs articles, OMI, discuter gen-spec en termes de modélisation ER. Si vous savez comment traduire un modèle ER dans un modèle relationnel, et de là aux tables SQL, vous saurez quoi faire une fois qu'ils vous montrent comment modéliser gen-spec dans ER.

Si vous google uniquement sur « gen-spec », la plupart de ce que vous verrez est orienté objet, non orienté relationnelle. Ce genre de choses peut être utile aussi bien, aussi longtemps que vous savez comment surmonter l'objet désadaptation d'impédance relationnelle.

Votre conception est raisonnable et suit les règles de normalisation correctes. Vous pourriez manquer une table de véhicule avec un identifiant véhicule et le type (le « parent » pour Speedboats, les voitures et Gokarts ... où vous voulez garder des choses comme « DesignedByUserId »). Entre la table de véhicule et la table Speedboats est un - à -. Une relation, et entre le véhicule et hors-bord / Voiture / GoKarts il y a un 1-and-only-1 relation (à savoir un véhicule ne peut avoir une fiche pour hors-bord, voitures ou karts) ... bien que la plupart DBs ne proposent pas un mécanisme d'application facile pour cela.

Une règle de normalisation qui permet d'identifier ce genre de choses est qu'un champ devrait dépendre seulement de la clé primaire de la table. Dans une table consolidée où vedette rapide, les voitures et les résultats des tests sont stockés ensemble kart puis les voitures domaines connexes dépendent non seulement à la date de test, mais aussi sur le type id vechicle et véhicule. La clé primaire de la table des résultats de test est la date de test + id du véhicule et le type de véhicule n'est pas ce qui fait la ligne de données de test uniques (c.-à-est de toute façon de procéder à un test sur 01/01/200912:. H 30 sur un véhicule spécifique qui est à la fois un bateau rapide et voiture ... Nope ... ne peut pas être fait).

Je ne suis pas expliquer la règle de normalisation particularily bien ... mais 3e / 4e / 5e règles de formes normales me confond toujours quand je lis les descriptions formelles. L'un d'entre eux (3/4/5) porte sur les champs en fonction de la clé primaire et que la clé primaire. La règle fait l'hypothèse que la clé primaire a été correctement identifié (defininh correctement la clé primaire est beaucoup trop facile à faire).

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top