Pregunta

Suponga que está configurando una base de datos para almacenar los datos de las pruebas de choque de varios vehículos. Desea almacenar los datos de las pruebas de choque para lanchas, automóviles, y karts.

Se puede crear tres mesas separadas: SpeedboatTests, CarTests y GokartTests. Sin embargo, una gran cantidad de sus columnas van a ser los mismos en cada tabla (por ejemplo, la identificación de empleado de la persona que realiza el examen, la dirección de la colisión (frontal, lateral, trasero), etc.). Sin embargo, un montón de columnas será diferente, por lo que no quiere sólo hay que poner todos los datos de prueba en una sola tabla, ya que tendrá un par de columnas bastantes que siempre será nulo para lanchas rápidas, un buen número que siempre nulo para los coches, y unos cuantos que siempre será nulo para karts.

Digamos que usted también desea almacenar alguna información que no está directamente relacionado con las pruebas (como la identificación de empleado del diseñador de lo que se está probando). Estas columnas no parecen derecho a poner en una mesa de "pruebas" en absoluto, sobre todo porque van a repetirse para todas las pruebas en el mismo vehículo.

Permítanme ilustrar una posible disposición de mesas, para que pueda ver las cuestiones planteadas.

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

Lo que es bueno / malo de esta estructura y cuál sería la mejor forma de implementar algo como esto?

¿Qué pasa si también hay alguna información que se aplica a todos los vehículos que prefiere tener en una mesa de Vehículos? Sería la tabla a continuación CarTests ser algo como ...

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)

Esto se acaba convirtiendo en un desastre real que parece. ¿Cómo debe ser algo como esto creó?

¿Fue útil?

Solución

El diseño type y id_in_type se llama Asociaciones polimórficos . Este diseño rompe las reglas de normalización de múltiples maneras. Por lo menos, debería ser una señal de alerta que no pueden declara una verdadera restricción de clave externa, debido a que el id_in_type puede hacer referencia a cualquiera de varias tablas.

Aquí hay una mejor manera de definir las tablas:

  • Hacer una Vehicles tabla resumen para proporcionar un punto de referencia abstracta para todos los sub-tipos de vehículos y pruebas de vehículos.
  • Cada vehículo subtipo tiene una clave principal que no incremento automático, sino que hace referencia a Vehicles.
  • Cada prueba subtipo tiene una clave principal que no incremento automático, sino que hace referencia a Tests.
  • Cada prueba sub-tipo también tiene una clave externa al vehículo sub-tipo correspondiente.

A continuación se muestra 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)
);

Se puede declarar como alternativa Tests.vehicle_id que hace referencia a Vehicles.vehicle_id y deshacerse de las claves externas vehicle_id en cada tabla de prueba sub-tipo, pero que permita anomalías, como una prueba de lancha rápida que hace referencia el identificador de un kart.

Otros consejos

Para las jerarquías de herencia de asignación a las tablas de bases de datos, creo que Martin Fowler expone las alternativas bastante bien en sus patrones de libros de arquitectura de aplicación empresarial.

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

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

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

Si el número de campos / columnas adicionales es pequeño para subclases, entonces la herencia única tabla suele ser el más simple de tratar.

Si utiliza PostgreSQL para su base de datos y que está dispuesto a atarse a una función de base de datos específica, es compatible con la herencia de tablas directamente:

http://www.postgresql.org/docs/8.3/ estático / ddl-inherit.html

Me dividirla en diferentes mesas, por ejemplo, Vehículo (ID, tipo, etc.) VehicleAttributes () IDVehículo, AttributeID, Valor), CrashTestInfo (IDVehículo, CrashtestID, fecha, etc.) CrashtestAttributes (CrashTestID, AttributeID, Valor)

O en lugar de atributos, tablas separadas para cada conjunto de detalle similar que debe ser registrada.

Si está utilizando SQLAlchemy , un mapeador objeto-relacional para Python, puede configurar la forma en jerarquías de herencia se asignan a las tablas de bases de datos . Objeto-relacionales creadores de mapas son buenos para la domesticación de SQL de otro modo tedioso.

Su problema podría ser una buena opción para las tablas verticales. En lugar de almacenar todo en el esquema, almacenar el tipo de objeto y la clave primaria de una tabla y tuplas clave / valor para cada objeto en otra mesa. Si realmente estaban almacenando las pruebas de autos, esta configuración podría hacer que sea mucho más fácil añadir nuevos tipos de resultados.

Haga una búsqueda en Google sobre "Gen-spec modelado relacional". Usted encontrará artículos sobre cómo configurar tablas que almacenan los atributos de la entidad generalizada (lo que los programadores OO podríamos llamar la superclase), tablas separadas para cada una de las entidades especializadas (subclases), y el uso de claves externas para vincularlo todos juntos.

Los mejores artículos, OMI, discutir gen-spec en términos de modelado ER. Si usted sabe cómo traducir un modelo ER en un modelo relacional, y de allí a las tablas SQL, usted sabrá qué hacer una vez que te muestran cómo modelar gen-spec en ER.

Si sólo Google el "gen-spec", la mayor parte de lo que ves es orientado a objetos, no relacional orientado. Eso puede ser útil también, como siempre que se sepa cómo superar el objeto relacional falta de concordancia.

Su diseño es razonable y está siguiendo las reglas de normalización correctas. Es posible que falte una mesa de vehículo con una ID de vehículo y tipo (es decir, el "padre" de lanchas rápidas, coches y Gokarts ... el lugar donde quiere guardar cosas por el estilo "DesignedByUserId"). Entre la mesa de vehículo y la mesa Speedboats es un uno - a -. Vehículo una relación, y entre y Speedboat / Coches / GoKarts hay una, y de sólo-1 1 relación (es decir, un vehículo sólo puede tener 1 registro para lancha rápida, coches o karts) ... aunque la mayoría de la db no ofrecen un mecanismo de aplicación fácil para esto.

Una regla de normalización que ayuda a identificar este tipo de cosas es que un campo debe depender sólo de la clave primaria de la tabla. En un cuadro consolidado en lancha rápida, coches, y kart resultados de las pruebas se almacenan juntos, entonces los coches de los campos relacionados no sólo dependen de la fecha de la prueba, sino también en el tipo de ID vechicle y el vehículo. La clave principal para la tabla de resultados de la prueba es la fecha del examen + Identificación del vehículo, y el tipo de vehículo no es lo que hace que la fila de datos única prueba (es decir, hay alguna forma de llevar a cabo una prueba en 01/01/200912:. 30pm en un vehículo específico que es a la vez una lancha rápida y el coche ... pues no ... no se puede hacer).

No estoy explicando la regla de normalización particularily bien ... pero / 4to / 5to reglas 3ª formas normales siempre me confunde al leer las descripciones formales. Uno de los (tercera / cuarta / quinta) se ocupa de los campos, dependiendo de la clave primaria y sólo la clave principal. La regla de hacer la suposición de que la clave principal se ha identificado correctamente (incorrectamente defininh la clave principal es demasiado fácil de hacer).

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top