【问题标题】:Implementing many-to-many with one "primary" value用一个“主要”值实现多对多
【发布时间】:2011-04-21 01:10:25
【问题描述】:
我有很多产品,每个产品都可以分为多个类别。
products: id, ...
products_categories: product_id, category_id
categories: id, ...
现在我想拥有许多产品,每个产品都有一个主类别和 0 个或多个辅助类别。我可以想到两种在 SQL 中对此建模的方法。
将is_primary 列添加到products_categories
或者
将primary_category_id 列添加到products
在纯 SQL 和/或 ActiveRecord 中实现此功能的最佳方法是什么?我正在使用 PostgreSQL,这是值得的。
【问题讨论】:
标签:
sql
ruby-on-rails
postgresql
activerecord
【解决方案1】:
除非我有充分的理由选择 2(例如获得主要类别时额外加入的成本),否则我会选择第一个选项
原因:您可能需要将主要类别添加到 product_category 表中(以便在查询中以统一且简单的方式使用它,例如获取产品的所有类别)
选项 1 避免重复主要类别,因此更简单
【解决方案2】:
我会选择选项 (1)。这样做的原因是因为您的产品可以属于多个类别,关系属性(即它的“主要”类别)属于定义关系的表。
我什至会更进一步,建议不要将字段标记为“is_primary”,而应该将该字段标记为“association_type”。而不是仅仅添加一个位字段,而是使其成为一个整数字段,并定义所有关联类型。在您今天的情况下,只有两种关联类型 - 次要的和主要的。优点是这种设计更具可扩展性。如果明天要求您定义“主要”、“次要”和所有其他第三级类别,此设计将能够处理它,而不必添加另一个字段来指定“次要”字段。
【解决方案3】:
这实际上取决于您要完成的任务的具体细节。以下是在决定什么最适合您时需要考虑的一些事项。其他答案已经解决了第一种情况,所以我将重点关注第二种情况。
如果你有primary_category_id:
- 在
product 中有一个字段来告诉哪个category 是主要字段,这似乎比在每个product_category 中都有一个字段,其中1 在一行中,0 在每一行行,虽然 M.R. 使用 association_type 的建议听起来也很干净 - 但是你会有什么机会拥有“三级”类别?
- 进入主要类别稍微容易一些
- 很容易确保每个产品始终都有一个主要类别(只需输入字段
NOT NULL)
- 它会自动强制产品只能有一个主要类别
- 是否还应该将主要类别插入
products_categories?
- 这两个选项均未强制执行。
- 如果不这样做,查询所有类别会很尴尬
- 如果这样做,查询仍然很容易,但无需额外工作,无法保证主类别也插入到其他表中
如果您使用is_primary 方法,您应该以某种方式确保每个产品始终只有一个主要类别。
【解决方案4】:
每种方式的优缺点是什么?
选项 1。 我可以确定产品的主要类别确实是其类别之一。但可能存在确保产品不超过一个主要类别的问题。
选项 2。 这让我可以确保产品只有一个主要类别。但是我似乎没有办法确保它是同一产品的类别之一。
所以,我可能会选择第三个选项,使用表格Products_PrimaryCategories:
Products_PrimaryCategories: product_id, category_id
看起来和product_categories一样,但是有一些额外的属性:
product_id 具有关联的唯一索引,确保每个产品只能有一个主要类别;
(product_id, category_id) 是引用 products_categories (product_id, category_id) 的外键,确保产品的主要类别是 其 类别之一(这意味着 (product_id, category_id) 应该是 products_categories 的主要类别键)。