假设你是设立一个数据库来存储的碰撞测试的数据的各种车辆。你要存储数据的碰撞测试用快艇、轿车和卡丁车。

你可以创建的三份单独的表格:SpeedboatTests,CarTests,并GokartTests.但很多你的列都将是相同的,在每个表格(例如,员工身份的人员进行测试,向冲突(前面、侧面,后),等等)。然而,大量的列有所不同,所以你不想只是把所有的检验数据在一个单一的表,因为你会有不少列将永远是无用的快艇,好几个,这将永远是空的汽车,以及相当多的,总是会null卡丁车。

让我们说你还想要储存一些信息,是不是直接相关的试验(例如雇员身份证的设计师事情正在测试)。这些列似乎没有权利放在一个"测试",表在所有人,特别是因为它们只是重复所有的测试在同一车辆。

让我说明一种可能的安排的表格,所以你可以看到的问题的参与。

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

什么是好坏关于这个结构,这将是首选的方式执行这样的事情?

如果还有一些信息适用于所有车辆,你会喜欢在一个车辆表?会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)

这只是越来越成为一个皇家混乱,它似乎。应该如何像这样的东西可以成立?

有帮助吗?

解决方案

typeid_in_type 设计被称为 多态关联. 。这种设计以多种方式打破了标准化规则。如果不出意外的话,这应该是一个危险信号,您 不能 声明一个真正的外键约束,因为 id_in_type 可以引用几个表中的任何一个。

这是定义表的更好方法:

  • 制作一个抽象表 Vehicles 为所有车辆子类型和车辆测试提供抽象参考点。
  • 每个车辆子类型都有一个主键,该主键不会自动递增,而是引用 Vehicles.
  • 每个测试子类型都有一个主键,该主键不会自动递增,而是引用 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)
);

你也可以声明 Tests.vehicle_id 哪些参考文献 Vehicles.vehicle_id 并删除每个测试子类型表中的vehicle_id外键,但这将允许异常,例如引用gokart id的快艇测试。

其他提示

有关映射继承层次到数据库表,我觉得Martin Fowler的勾画出了相当的替代品以及在他的企业应用架构模式书

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

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

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

如果附加字段/列的数目是小的子类,那么单个表继承通常是最简单的处理。

如果你正在使用PostgreSQL为你的数据库和你愿不愿意把自己绑在一个特定的数据库功能,它支持表继承直接:

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

我将其拆分成不同的表,例如车辆(ID,类型等)VehicleAttributes()VehicleID,属性Id,值),CrashTestInfo(VehicleID,CrashtestID,日期等)CrashtestAttributes(CrashTestID,属性Id,值)

或者而不是属性,单独的表的每个组相似的细节应记录。

如果您使用 SQLAlchemy, 目关系映射对蟒蛇,你可以 配置如何,继承的层次结构映射数据库表.对象关系映射是好驯服,否则繁琐SQL。

你的问题可能是一个很好的适用于垂直表。而不是储存中的一切的架构,保存对象的类型和主要关键之一表和key/value组对每个对象中的另一个表中。如果你真的是储存汽车测试,这种设置将使它更容易添加新的种类的结果。

请在“根规格的关系建模”谷歌搜索。你会发现如何设置存储的通用实体(什么OO程序员可能调用父类),分别为每个专业实体表(子类),以及如何使用外键链接它的属性表文章都在一起。

最理想的用品,国际海事组织,讨论ER建模方面根规格。如果你知道如何翻译的ER模型转换为关系模型,并从那里向SQL表,你就知道该怎么做,一旦他们告诉你如何根规格的ER模型。

如果你只是在“根规格的”谷歌的大部分东西,你会看到的是面向对象的,而不是面向关系。你知道如何克服对象关系阻抗失配的东西可能是有用的,因为长。

您设计合理并按照正确的规范化规则。您可能忽略了车辆ID和类型车辆表(用于快艇,汽车即“父”,和卡丁车......在这里你会保持这样的东西“DesignedByUserId”)。车辆表和快艇表之间是一个一 - 至 - 一个关系,和之间的车辆和快艇/汽车/卡丁车存在1且仅-1的关系(即,车辆只能有用于快艇1个结果,汽车或卡丁车)......虽然大多数分贝的没有为此提供了一个简单的执法机制。

一个规范化规则,可帮助识别这些各种各样的事情是,一个字段应仅在表中的主键依赖。在快艇,汽车和gokart测试结果存储在一起,然后合并表相关领域的汽车,不仅在测试日期,但也对运载工具ID和车辆类型的依赖。对于测试结果表的主键是测试日期+车辆ID和车辆类型不是什么使测试数据行唯一的(即反正是有进行上01/01/200912一个试验:在一个特定的车辆30PM既快艇和汽车......都能跟得上...不能完成)。

我不解释规范化规则particularily很好......但3/4/5的正常形式的规则总是混淆了我,当我读到的正式描述。其中一个(第三/第四/第5次)的与取决于主键和只有主键字段的交易。该规则使该主键已经被正确识别的假设(不正确地defininh主键是太容易做)。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top