Domanda

Supponiamo che si stava configurando un database per memorizzare i dati di prova di crash di vari veicoli. Si desidera memorizzare i dati di crash test per motoscafi, auto e go-kart.

È possibile creare tre tabelle separate: SpeedboatTests, CarTests, e GokartTests. Ma un sacco di vostre colonne stanno per essere lo stesso in ogni tabella (ad esempio, l'id dipendente della persona che ha eseguito il test, la direzione della collisione (frontale, laterale, posteriore), etc.). Tuttavia, un sacco di colonne sarà diverso, in modo che non si vuole mettere solo tutti i dati di test in un unico tavolo perché avrete un bel paio di colonne che sarà sempre nullo per motoscafi, un bel po 'che sarà sempre essere nullo per le auto, e un bel po 'che sarà sempre nullo per go-kart.

Diciamo che si desidera anche per memorizzare alcune informazioni che non è direttamente collegata ai test (come ad esempio l'id impiegato del progettista della cosa in fase di test). Queste colonne non mi sembra giusto mettere in una tabella "Test" a tutti, soprattutto perché essi saranno ripetute per tutti i test sullo stesso veicolo.

Vorrei illustrare una possibile disposizione dei tavoli, in modo da poter vedere le questioni coinvolte.

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

Ciò che è buono / cattivo su questa struttura e quale sarebbe il modo migliore di implementare qualcosa di simile?

E se ci fosse anche un po 'di informazioni che si applica a tutti i veicoli che si preferisce avere in una tabella Vehicles? Sarebbe il tavolo CarTests poi cercare qualcosa di simile ...

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)

Questa è solo di arrivare a essere un disastro reale sembra. Come dovrebbero qualcosa come questo essere impostato?

È stato utile?

Soluzione

Il design type e id_in_type si chiama polimorfiche Associazioni . Questo design rompe le regole di normalizzazione in più modi. Se non altro, dovrebbe essere una bandiera rossa che si non può dichiarare un vero e proprio vincolo di chiave esterna, perché il id_in_type può fare riferimento a una delle diverse tabelle.

Ecco un modo migliore di definire le tabelle:

  • Fare un tavolo Vehicles astratta di fornire un punto di riferimento astratto per tutti i sottotipi di veicoli e prove sui veicoli.
  • Ogni sotto-tipo di veicolo ha una chiave primaria che non si auto-incremento, ma invece fa riferimento a Vehicles.
  • Ogni sotto-tipo di test ha una chiave primaria che non si auto-incremento, ma invece fa riferimento a Tests.
  • Ogni sotto-tipo di test ha anche una chiave esterna alla corrispondente sub-tipo di veicolo.

Ecco DDL campione:

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

Si potrebbe in alternativa, dichiarare Tests.vehicle_id che fa riferimento Vehicles.vehicle_id e sbarazzarsi delle chiavi esterne vehicle_id in ogni tabella di test sotto-tipo, ma che avrebbe permesso anomalie, come ad esempio un test motoscafo che fa riferimento id di un gokart.

Altri suggerimenti

Per le gerarchie di ereditarietà mappatura alle tabelle del database, credo che Martin Fowler delinea le alternative abbastanza bene nel suo libro di modelli di Enterprise Application Architecture.

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

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

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

Se il numero di campi aggiuntivi / colonne è piccola per sottoclassi, allora singola ereditarietà delle tabelle di solito è il più semplice da affrontare.

Se stai usando PostgreSQL per il database e siete disposti a legarsi a una funzione specifica del database, supporta ereditarietà delle tabelle direttamente:

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

Vorrei suddividerlo in diverse tabelle, per esempio Vehicle (ID, tipo, ecc) VehicleAttributes () VehicleID, AttributeID, Value), CrashTestInfo (VehicleID, CrashtestID, data, ecc) CrashtestAttributes (CrashTestID, AttributeID, Value)

O, piuttosto che gli attributi, tabelle separate per ogni set di dettaglio simile che deve essere registrato.

Se si utilizza SQLAlchemy , un mapper object-relational per Python, puoi configurare la modalità di gerarchie di ereditarietà vengono mappati a tabelle del database . Object-relational mapper sono buone per domare SQL altrimenti noiosa.

Il tuo problema potrebbe essere una buona misura per le tabelle verticali. Invece di memorizzare tutto nello schema, memorizzare il tipo di oggetto e la chiave primaria in una tabella e tuple chiave / valore per ogni oggetto in un'altra tabella. Se fossi veramente memorizzazione test di auto, questa configurazione potrebbe rendere molto più facile aggiungere nuovi tipi di risultati.

Fare una ricerca su google "modeling relazionale Gen-spec". Troverete articoli su come impostare le tabelle che memorizzano gli attributi dell'entità generalizzata (quello che i programmatori OO potrebbe chiamare la superclasse), tabelle separate per ciascuno dei soggetti specializzati (sottoclassi), e come usare le chiavi esterne per collegarlo tutti insieme.

I migliori articoli, IMO, discutere Gen-spec in termini di modellazione ER. Se si sa come tradurre un modello ER in un modello relazionale, e di là a tabelle SQL, saprete cosa fare una volta che vi mostrano come modellare Gen-spec in ER.

Se hai appena Google su "Gen-spec", la maggior parte di quello che vedrete è orientato agli oggetti, non relazionale orientato. Quella roba può essere utile così, fino a quando si sa come superare l'oggetto relazionale disadattamento di impedenza.

Il tuo disegno è ragionevole e sta seguendo le regole di normalizzazione corretti. Potrebbe mancare un tavolo di veicoli con un ID e tipo di veicolo (cioè il "genitore" per motoscafi, automobili, e Gokarts ... dove ti piacerebbe tenere roba come "DesignedByUserId"). Tra la tavola del veicolo e la tabella motoscafi è uno - a -. Un rapporto, e tra veicoli e motoscafo / Auto / GoKarts c'è una e unica 1 1-relazione (cioè un veicolo può avere solo 1 record per motoscafo, auto o go kart) ... se la maggior parte delle db non offrono un meccanismo di esecuzione facile per questo.

Una regola di normalizzazione che aiuta a identificare questo genere di cose è che un campo dovrebbe dipendere solo dalla chiave primaria della tabella. In una tabella consolidata qualora motoscafo, automobili, e gokart risultati dei test sono memorizzati insieme quindi le vetture campi correlati dipendono non solo dalla data di prova, ma anche dal tipo vechicle id e veicolo. La chiave primaria della tabella dei risultati del test è data prova + id veicolo e tipo di veicolo non è ciò che rende la riga di dati di test unica (cioè c'è comunque di effettuare un test su 01/01/200912:. 30pm su uno specifico veicolo che è sia un motoscafo e auto ... no ... non può essere fatto).

Non sto spiegando la regola di normalizzazione particularily bene ... ma 3 ° / 4 ° / 5 ° regole forme normali mi confonde sempre quando ho letto le descrizioni formali. Uno di quelli (3 ° / 4 ° / 5 °) si occupa di campi a seconda della chiave primaria e solo la chiave primaria. La regola fare l'ipotesi che la chiave primaria è stato identificato correttamente (defininh in modo non corretto la chiave primaria è fin troppo facile da fare).

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top