【问题标题】:Two tables to one table as relation两张表对一张表作为关系
【发布时间】:2019-10-28 18:16:22
【问题描述】:

我在设计我的数据库的一部分以及它们之间的关系时遇到了一些麻烦。

我的实体是:

  • 车辆 -> 1:1 -> 价格
  • 自行车 -> 1:1 -> 价格

选项 A:

创建 2 个表

车辆表

+----------------+---------+
|      NAME      |  TYPE   |
+----------------+---------+
| Id             | uuid    |
| brand          | varchar |
| model          | varchar |
| attribute1     | varchar |
| price          | float   |
| discount float |         |
| locale varchar |         |
+----------------+---------+

自行车桌

+----------------+---------+
|      NAME      |  TYPE   |
+----------------+---------+
| Id             | uuid    |
| vendor         | varchar |
| attribute1     | varchar |
| attribute2     | varchar |
| attribute3     | varchar |
| price          | float   |
| discount float |         |
| locale varchar |         |
+----------------+---------+

选项 B

创建 3 个表

车辆表

+----------------+---------+
|      NAME      |  TYPE   |
+----------------+---------+
| Id             | uuid    |
| brand          | varchar |
| model          | varchar |
| attribute1     | varchar |
+----------------+---------+

自行车桌


+----------------+---------+
|      NAME      |  TYPE   |
+----------------+---------+
| Id             | uuid    |
| vendor         | varchar |
| attribute1     | varchar |
| attribute2     | varchar |
| attribute3     | varchar |
+----------------+---------+

价格表

+----------------+-------+
|      NAME      | TYPE  |
+----------------+-------+
| vehicle_id     | FK    |
| bike_id        | FK    |
| price          | float |
| discount float |       |
| locale varchar |       |
+----------------+-------+

选项 C

创建 4 个表

车辆表

+----------------+---------+
|      NAME      |  TYPE   |
+----------------+---------+
| Id             | uuid    |
| brand          | varchar |
| model          | varchar |
| attribute1     | varchar |
+----------------+---------+

车辆价格表

+----------------+-------+
|      NAME      | TYPE  |
+----------------+-------+
| vehicle_id     | FK    |
| price          | float |
| discount float |       |
| locale varchar |       |
+----------------+-------+

自行车桌


+----------------+---------+
|      NAME      |  TYPE   |
+----------------+---------+
| Id             | uuid    |
| vendor         | varchar |
| attribute1     | varchar |
| attribute2     | varchar |
| attribute3     | varchar |
+----------------+---------+

自行车价格表

+----------------+-------+
|      NAME      | TYPE  |
+----------------+-------+
| bike_id        | FK    |
| price          | float |
| discount float |       |
| locale varchar |       |
+----------------+-------+

注意:我确实简化了车辆和自行车表(我不能将它们合并到一个表中,例如“产品”)

性能模式的角度来看,我们将成为最佳设计?

【问题讨论】:

    标签: database postgresql algorithm design-patterns


    【解决方案1】:

    如果您需要在单个表中包含所有价格(用于排序等),选项 B 很好,尽管您可能希望对价格表有一个约束,即每行准确引用车辆或自行车,但两者都没有,也没有。

    请注意,您可以在此处购买没有价格的车辆或自行车。

    另一种方法是反转外键关系,并拥有三个这样的表:

    PRODUCTS TABLE
    +----------------+---------+
    |      NAME      | TYPE    |
    +----------------+---------+
    | product_id     | uuid    |
    | price          | float   |
    | discount       | float   |
    | locale         | varchar |
    +----------------+---------+
    
    VEHICLES TABLE
    +----------------+---------+
    |      NAME      |  TYPE   |
    +----------------+---------+
    | Id             | uuid,FK |
    | brand          | varchar |
    | model          | varchar |
    | attribute1     | varchar |
    +----------------+---------+
    
    BIKES TABLE
    +----------------+---------+
    |      NAME      |  TYPE   |
    +----------------+---------+
    | Id             | uuid,FK |
    | vendor         | varchar |
    | attribute1     | varchar |
    | attribute2     | varchar |
    | attribute3     | varchar |
    +----------------+---------+
    

    现在您可以拥有既不是自行车也不是车辆的产品,并且您可以同时拥有自行车和车辆的产品。缺点是对于给定的产品,您不知道它是什么。

    另一方面,该方案允许强制每辆车和每辆自行车都有价格。


    既然您询问了模式的观点,那么从这方面的解决方案是使用composite type for your prices。价格不是一个实体(具有自己的身份),它只是自行车和车辆使用的一个值。这里我们只有两个表:

    PRICE _TYPE_
    +----------------+---------+
    |      NAME      | TYPE    |
    +----------------+---------+
    | value          | float   |
    | discount       | float   |
    | locale         | varchar |
    +----------------+---------+
    
    VEHICLES TABLE
    +----------------+---------+
    |      NAME      |  TYPE   |
    +----------------+---------+
    | Id             | uuid,FK |
    | brand          | varchar |
    | model          | varchar |
    | attribute1     | varchar |
    | price          | price   |
    +----------------+---------+
    
    BIKES TABLE
    +----------------+---------+
    |      NAME      |  TYPE   |
    +----------------+---------+
    | Id             | uuid,FK |
    | vendor         | varchar |
    | attribute1     | varchar |
    | attribute2     | varchar |
    | attribute3     | varchar |
    | price          | price   |
    +----------------+---------+
    

    这将等同于您的解决方案 A,尽管具有更好的代码重用性。此外,price 字段现在可以作为一个完整结构为空,而不是在其各个部分上。

    但是,从性能和可用性的角度来看,我建议避免使用复合类型,因为使用它们很麻烦。您宁愿使用解决方案 A 并手动保持与价格相关的列定义同步。

    【讨论】:

      【解决方案2】:

      我会选择选项 B,因为您不能将两者合并。这样您就可以拥有多个价格和/或保留未来价格变化的记录。

      【讨论】:

      • 谢谢,但我知道我的关系永远是 1:1。通过设计生成 NULL 值是一种不好的做法吗?我的意思是 PRICES_TABLES 将有一个 FK 为 NULL(每次 vehicle_id 不为空时,bike_id 将为空,反之亦然)
      【解决方案3】:

      如果您可以将 id 范围分为两部分(例如,小于 50000000 的自行车和大于 50000000 的车辆,则选择选项 B。这样可以避免创建未使用的空列。
      否则,选项 C 为更改提供了更好的灵活性,因为未来自行车和汽车所需的数据会发生不同的变化。
      您还可以通过在价格表中添加额外的 DateTime 列来保留价格历史记录。

      【讨论】:

        猜你喜欢
        • 2019-12-14
        • 2018-01-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-09-04
        • 2019-11-15
        • 1970-01-01
        • 2020-10-12
        相关资源
        最近更新 更多