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

标签 database-design polymorphic-associations class-table-inheritance

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

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

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

让我举例说明一种可能的表格排列方式,以便您了解所涉及的问题。

快艇
身份证 | col_about_speedboats_but_not_tests1 | col_about_speedboats_but_not_tests2

汽车
身份证 | col_about_cars_but_not_tests1 | col_about_cars_but_not_tests2

卡丁车
身份证 | col_about_gokarts_but_not_tests1 | col_about_gokarts_but_not_tests2

测试
身份证 |类型 | id_in_type | col_about_all_tests1 | col_about_all_tests2
(id_in_type 将引用接下来三个表之一的 id 列,
取决于类型的值)

快艇测试
身份证 | speedboat_id | col_about_speedboat_tests1 | col_about_speedboat_tests2

汽车测试
身份证 | car_id | col_about_car_tests1 | col_about_car_tests2

卡丁车测试
身份证 | gokart_id | col_about_gokart_tests1 | col_about_gokart_tests2

这种结构有什么好处/坏处,实现这样的东西的首选方式是什么?

如果还有一些适用于您希望在 Vehicles 表中包含的所有车辆的信息怎么办? CarTests 表会看起来像......

身份证 |车辆_id | ...

使用像这样的 Vehicles 表:
身份证 |类型 | id_in_type
(id_in_type 指向快艇、汽车或卡丁车的 ID)

看起来,这简直是一团乱麻。应该如何设置这样的东西?

最佳答案

typeid_in_type设计被称为Polymorphic Associations .这种设计以多种方式打破了规范化规则。如果不出意外,它应该是一个危险信号,您不能声明真正的外键约束,因为 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 的快艇测试。

    关于database-design - 类似于数据库设计中的继承,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/554522/

    相关文章:

    mysql - 为什么在数据库中使用 bool 标志不好?应该用什么代替?

    php - 如何在 Doctrine2 中为类表继承指定外键列?

    doctrine-orm - 如何转换实体留下它的id

    sql - 相关表中值的部分索引,而不是外键?

    database - Django - 设计模型关系 - 管理界面和内联

    php - Phalcon:多态关联

    ruby-on-rails - 在 Rails 中对应用程序进行建模 - 混合 STI 和多态关联

    mysql - 如何在 Doctrine 中将鉴别器列定义为类表继承的 ENUM?

    database - 在数据库中存储大量(简单)时间线图数据

    ruby-on-rails - ActiveRecord - 查询多态关联