【问题标题】:Database column(s) that relate to one of multiple tables与多个表之一相关的数据库列
【发布时间】:2014-06-07 20:58:45
【问题描述】:

我觉得这是一个非常基本的问题,尽管我已经在数据库方面做了很多工作,但我仍然想不出一个好的方法。谷歌搜索时似乎也找不到任何东西。

假设我有一堆表,每个表都描述了一种项目。

例如:

Table candles:
id█  name  █length█diameter▌burntime▌
▀▀█▀▀▀▀▀▀▀▀█▀▀▀▀▀▀█▀▀▀▀▀▀▀▀█▀▀▀▀▀▀▀▀▌
1 █ candle1█54    █  6     █  180   ▌
69█ candle2█29    █  16    █  145   ▌
80█ candle3█100   █ 40     █  110   ▌


Table coasters:
id█  name  █thickness█diameter▌color   ▌
▀▀█▀▀▀▀▀▀▀▀█▀▀▀▀▀▀▀▀▀█▀▀▀▀▀▀▀▀█▀▀▀▀▀▀▀▀▌
1 █coaster1█5        █  20    █#ffffff ▌
6 █coaster2█8        █  41    █#ff0051 ▌
8 █coaster3█7        █ 38     █#002199 ▌


Table baskets:
id█  name  █size█
▀▀█▀▀▀▀▀▀▀▀█▀▀▀▀█
1 █basket1 █5   █
2 █basket2 █8   █
3 █basket3 █22  █

现在我有另一张桌子。我们称之为购物车。此表中的每条记录都需要保存这些项目的数组。这是我不知道如何进行的地方。 所以我需要一个多对多的关系,这意味着我需要一个连接/数据透视表。 但是怎么做呢?

我应该为每种类型的项目设置一个连接表吗?外键用于购物车 ID,外键用于蜡烛/杯垫等的记录 ID。 然后在列出购物车的内容时,我需要检查每个连接表,每种类型的项目都有一个。对我来说听起来不是很干净。

或者我应该只有一个联结表,其中有一列用于表名,另一列用于记录 ID? 看起来也很脏。

我想有更好的方法可以做到这一点,但我想不出。 这应该怎么做?

【问题讨论】:

  • 或者我应该只有一个联结表,其中有一列是表名,一列是记录 ID? 是的,如果你已经拥有所有这些桌子!你不喜欢它的什么?
  • 如果你打算有一个'shoppingcart'表,那么你需要区分物品作为产品,它们在哪里有数量、价格等,以及它们的产品细节,这就是你所拥有的更多。因此,也许可以考虑一个链接回单个详细信息的产品表,但也存储库存中的数量、价格等。目前您的模型的主要弱点是新产品类型需要一个全新的表。另见:stackoverflow.com/questions/9125029/… 例如。
  • 实际上,更好的解决方案是将当前内容存储在两个表中,例如 goods (id, name) 和 goods-properties (id, goodsId, property, value),其中“财产”将是例如size 和值将是例如5(用于篮子 1)
  • 您应该将所有产品及其属性保存在一个表中,在第二个表中您应该保留他们的库存,并且您应该将您的订单保存在另一个表中..所有表应该通过外部相互链接钥匙....
  • @TomasPastircak 您的第一条评论.. 对我来说,让每个联结记录都有一个表名的 (varchar?-) 字段,而不是一个漂亮的 32 位整数 id,这感觉很不干净就像我习惯的那样。那么不可能为这些中的任何一个添加索引外键?

标签: mysql sql database


【解决方案1】:

解决此问题的一种潜在方法是将您拥有的项目视为对象,然后考虑如何对这些项目进行关联建模。如果您将所有项目视为具有属性、具有值的对象,那么这是存储此信息的通用模式。

这通常被称为O/R Mapping

一个简单的关系示例可能如下所示:

对象 - 定义您的所有项目

+----+----------+---------+
| Id |   Name   |  Type   |
+----+----------+---------+
|  1 | Candle1  | Candle  |
|  2 | Coaster1 | Coaster |
|  3 | Basket1  | Basket  |
+----+----------+---------+

ObjectProperty - 定义所有属性

+----+-----------+----------+
| Id |   Name    | DataType |
+----+-----------+----------+
|  1 | Length    | Float    |
|  2 | Diameter  | Float    |
|  3 | Burntime  | Float    |
|  4 | Thickness | Float    |
|  5 | Color     | String   |
|  6 | Size      | Int      |
+----+-----------+----------+

ObjectPropertyValue - 定义对象和属性之间的关系,以及值

+----+----------+------------+----------+------------+-----------+-------------+
| Id | ObjectId | PropertyId | ValueInt | ValueFloat | ValueDate | ValueString |
+----+----------+------------+----------+------------+-----------+-------------+
|  1 |        1 |          1 | NULL     | 54.0       | NULL      | NULL        |
|  2 |        1 |          2 | NULL     | 29.0       | NULL      | NULL        |
|  3 |        3 |          6 | 5        | NULL       | NULL      | NULL        |
+----+----------+------------+----------+------------+-----------+-------------+

要检索单个对象的所有值,您可以运行如下查询:

SELECT          OP.Name,
                OP.DataType,
                OPV.ValueInt,
                OPV.ValueFloat,
                OPV.ValueDate,
                OPV.ValueString

FROM            ObjectProperty OP
INNER JOIN      ObjectPropertyValue OPV ON OP.Id = OPV.PropertyId

WHERE           OPV.ObjectId = 1

以这种格式存储信息有几个优点:

  • 它是可扩展的,因此您不需要每次创建新对象时都需要一个新表 类型来了
  • 您可以根据需要拥有任意数量的属性 对象
  • 键入属性值意味着您仍然可以进行相关查询 基于数据类型

即搜索所有长度小于 50 的蜡烛:

SELECT      O.Id, 
            O.Name,
            OP.Name,
            OPV.ValueFloat 
FROM        Object O
INNER JOIN  ObjectPropertyValue OPV ON O.Id = OPV.ObjectId
INNER JOIN  OpjectProperty OP ON OPV.PropertyId = OP.Id

WHERE       OP.Name = 'Length'
AND         O.Type = 'Candle'
AND         OPV.ValueFloat <= 50.0;

不过也有缺点:

  • 如果没有动态 sql,很难动态构建查询,因为您首先需要知道要在特定对象上查找什么样的属性,然后在 ObjectPropertyValue 中选择要搜索的适当列
  • 将对象压缩到通用结构中有时会使非常简单的操作变得非常复杂。例如,比较在表结构中获取蜡烛与上面的查询的难易程度。

还有其他缺点,但开始详细阅读此主题的好地方是O/R Mapping and Relational Data

最后,解决这个问题的另一种解决方案是NoSQL, an alternative mechanism to storing objects relationally.的概念

Jeff Atwood 也有关于这个主题的 great article

【讨论】:

    猜你喜欢
    • 2012-01-07
    • 2015-11-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-30
    • 1970-01-01
    • 2011-04-22
    • 1970-01-01
    相关资源
    最近更新 更多