Database design 类似于数据库设计中的继承

Database design 类似于数据库设计中的继承,database-design,polymorphic-associations,class-table-inheritance,Database Design,Polymorphic Associations,Class Table Inheritance,假设您正在建立一个数据库来存储各种车辆的碰撞测试数据。您希望存储快艇、汽车和卡丁车的碰撞测试数据 您可以创建三个单独的表:SpeedboatTests、CarTests和GokartTests。但每个表中的许多列都是相同的(例如,执行测试的人员的员工id、碰撞方向(前、侧、后)等等)。然而,很多列是不同的,所以你不想把所有的测试数据都放在一个表中,因为你会有很多列对于快艇总是空的,很多对于汽车总是空的,还有很多对于卡丁车总是空的 假设您还希望存储一些与测试不直接相关的信息(例如被测试对象的设计者

假设您正在建立一个数据库来存储各种车辆的碰撞测试数据。您希望存储快艇、汽车和卡丁车的碰撞测试数据

您可以创建三个单独的表:SpeedboatTests、CarTests和GokartTests。但每个表中的许多列都是相同的(例如,执行测试的人员的员工id、碰撞方向(前、侧、后)等等)。然而,很多列是不同的,所以你不想把所有的测试数据都放在一个表中,因为你会有很多列对于快艇总是空的,很多对于汽车总是空的,还有很多对于卡丁车总是空的

假设您还希望存储一些与测试不直接相关的信息(例如被测试对象的设计者的员工id)。这些列似乎根本不适合放在“测试”表中,特别是因为它们将在同一辆车上的所有测试中重复

让我举例说明一种可能的表格安排,以便您可以看到所涉及的问题

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 快艇 id | col|u关于快艇但不测试1 | col|u关于快艇但不测试2 汽车 id | col|u关于车但不关于测试1 | col|u关于车但不关于测试2 戈卡茨 id | col|u关于gokarts但不测试1 | col|u关于gokarts但不测试2 测验 id | type | id | u in | u type | col | u关于| u all | u tests1 | col | u关于| u all | u tests2 (id_in_type将指下三个表之一的id列, 取决于类型的值) 快艇运动员 id |快艇| id | col | U快艇|测试1 | col | U快艇|测试2 卡特尔 id | car | id | col | u关于| car | u测试1 | col | u关于| car | u测试2 戈卡特斯 id | gokart | id | col | u关于| gokart | u测试1 | col | u关于| gokart | u测试2 这种结构的优点/缺点是什么?实现这种结构的首选方式是什么

如果车辆表中还有一些适用于所有车辆的信息,该怎么办?CarTests表是否看起来像

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) 身份证|车辆|身份证|。。。 对于这样的车辆表: id |类型| id |类型 (id_in_type指向快艇、汽车或卡丁车的id)
这看起来就像是一场皇室的混乱。应该如何设置这样的内容?

我会将其分为不同的表,例如车辆(ID、类型等)车辆属性()车辆ID、属性ID、值)、碰撞信息(车辆ID、碰撞ID、日期等)碰撞属性(碰撞ID、属性ID、值)


或者,与其说是属性,不如说是应该记录的每一组类似细节的单独表。

为了将继承层次结构映射到数据库表,我认为Martin Fowler在他的《企业应用程序体系结构模式》一书中很好地阐述了备选方案

如果子类的附加字段/列的数量很少,那么单表继承通常是最容易处理的

如果您在数据库中使用PostgreSQL,并且愿意将自己绑定到特定于数据库的功能,则它直接支持表继承:


您的设计是合理的,并且遵循正确的规范化规则。您可能缺少一个带有车辆Id和类型的车辆表(例如,快艇、汽车和Gokart的“父项”…您可以在其中保存“DesignedByUserId”之类的内容)。车辆表和快艇表之间是一对一的关系,车辆和快艇/汽车/卡丁车之间是一对一的关系(即一辆车辆只能有一条快艇、汽车或卡丁车记录)。。。尽管大多数db并没有为此提供简单的执行机制

帮助识别这类内容的一个规范化规则是,字段应该只依赖于表的主键。在一个合并表中,快艇、汽车和gokart测试结果存储在一起,那么与汽车相关的字段不仅取决于测试日期,还取决于车辆id和车辆类型。测试结果表的主键是测试日期+车辆id,而车辆类型并不是测试数据行唯一的原因(即,是否有必要在2001年1月1日下午12:30对一辆既有快艇又有汽车的特定车辆进行测试……不……无法完成)


我没有特别好地解释规范化规则。。。但是,当我阅读正式描述时,第3/4/5范式规则总是让我感到困惑。其中一个(第三/第四/第五)处理的字段取决于主键,并且只处理主键。该规则假设主键已被正确识别(主键的定义不正确太容易实现)。调用
类型
id\u类型
设计。这种设计以多种方式打破了规范化规则。如果没有其他内容,那么您就不能声明真正的外键约束,因为
id\u in\u type
可能引用多个表中的任何一个

以下是定义表的更好方法:

  • 制作一个抽象表
    车辆
    ,为所有车辆子类型和车辆测试提供一个抽象参考点
  • 每个车辆子类型都有一个主键,该主键不自动递增,而是引用
    车辆
  • 每个测试子类型都有一个主键,该主键不自动递增,而是引用
    Tests
  • 每个测试子类型还具有对应车辆子类型的外键
以下是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)
);
您也可以声明引用
车辆.vehicle\u id
测试.vehicle\u id
,并清除每个测试子类型表中的车辆id外键,但这将允许出现异常,例如引用gokart id的快艇测试。

进行谷歌搜索