Postgres 数据库:如何对可以具有多个值并与其他两个实体有关系的多个属性建模
Postgres database: how to model multiple attributes that can have also multiple value, and have relations to other two entities
我有三个实体,项目、类别和属性。
一个Item
可以是一个或多个Categories
,所以有N:M关系
Item ItemCategories Categories
id name item_id category_id id name
1 alfa 1 1 1 chipset
1 2 2 interface
一个 Item
可以有多个 Attributes
,具体取决于它们所在的 'Categories'。
例如,Category
'chipset' 中的项目可以具有以下属性:'interface'、'memory' 'tech'.
这些属性有一组不经常更改的预定义值,但它们可以更改。
例如:'memory'只能是ddr2,ddr3,ddr4.
Attributes CategoryAttributes
id name values category_id attribute_id
1 memory {ddr2, ddr3, ddr4} 1 1
'chipset' Category
中的 Item
可以访问 Attribute
并且只能具有 Null 或属性的预定义值。
我想使用 Enum
或 Json
作为属性值,但我还有另外两个条件:
项目属性
item_id attribute_id value
1 1 {ddr2, ddr4}
1) 如果一个Attribute出现在2个Categories中,一个Ithe同时出现在两个Categories中,一个属性只能显示一次。
2) 我需要使用rank
的值,所以如果一个项目出现两个对应的属性值,如果只有一个,则排名应该更大,或者该值不存在。
3)为属性创建单独的表不是一种选择,因为数量不固定,而且可能很大。
所以,我不知道数据库设计中的最佳选择是限制值并用于订单排名。
您所描述的问题是一个典型的开放模式或垂直数据库,这是某种 EAV
模型的经典用例。
EAV 是一个复杂而强大的范例,它允许潜在的开放模式,同时尊重 database normal forms 并允许拥有您需要的东西:根据同一实体的特定实例拥有可变数量的属性。
这就是使用关系数据库的电子商务中通常会发生的情况,因为不同的产品具有不同的属性(例如口红有颜色,但对于硬盘驱动器,您可能不关心颜色而是容量)而且它不具有一个属性 table 是有意义的,因为数字不固定并且可以很大,并且对于大多数行,会有很多 NULL
值(这是稀疏矩阵的数学概念,在数据库中看起来很丑 table)
您可以看一下 Magento DB Model, a true reference in pure EAV at scale, or Wikipedia,但您可能稍后再做,现在,您只需要基础知识:
基本思想是在单个 table.
中将属性及其对应值存储为行而不是列
在更简单的实现中,table 至少有三列:entity
(通常是实体的外键,或实体 type/category),attribute
(这可以是一个字符串,o 在更复杂的系统中是一个外键)和 value
。
在我之前的示例中,过于简单化了,我们可以有一个像这样的 table,它列出了
的属性名称及其值
Item table Attributes table
+------+--------------+ +-------------+-----------+-------------+
| id | name | | item_id | attribute | value |
+------+--------------+ +-------------+-----------+-------------+
| 1 | "hard drive" | | 2 | "color" | "red" |
+------+--------------+ +-------------+-----------+-------------+
| 2 | "lipstick" | | 2 | "price" | 10 |
+------+--------------+ +-------------+-----------+-------------+
| 1 | "capacity"| "1TB" |
+-------------+-----------+-------------+
| 1 | "price" | 200 |
+-------------+-----------+-------------+
So for every item, you can have a list of attributes.
由于你的模型比较复杂,约束也比较多,所以我们需要适配这个模型。
- 由于您想限制可能的值,因此您需要 table 值
- 因为你会有一个值table,这些值必须引用一个属性,所以你需要属性有一个id,所以你会有一个属性table
- 为了明确和严格什么类别有什么属性,你需要一个类别属性table
有了这个,你最终会得到类似
的东西
类别table
类别 ID 和名称列表
+------+--------------+
| id | name |
+------+--------------+
| 1 | "chipset" |
+------+--------------+
| 2 | "interface" |
+------+--------------+
属性table
属性 ID 列表及其名称
+------+--------------+
| id | name |
+------+--------------+
| 1 | "interface" |
+------+--------------+
| 2 | "memory" |
+------+--------------+
| 3 | "tech" |
+------+--------------+
| 4 | "price" |
+------+--------------+
类别-属性table
什么类别有什么属性。请注意,一个属性(即 4)可以属于 2 个类别
+--------------+--------------+
| attribute_id | category_id |
+--------------+--------------+
| 1 | 1 |
+--------------+--------------+
| 2 | 1 |
+--------------+--------------+
| 3 | 1 |
+--------------+--------------+
| 4 | 1 |
+--------------+--------------+
| 4 | 2 |
+--------------+--------------+
值table
每个属性的可能值列表
+----------+--------------+--------+
| value_id | attribute_id | value |
+-------------+-----------+--------+
| 1 | 2 | "ddr2" |
+----------+--------------+--------+
| 2 | 2 | "ddr3" |
+----------+--------------+--------+
| 3 | 2 | "ddr4" |
+----------+--------------+--------+
| 4 | 3 |"tech_1"|
+----------+--------------+--------+
| 5 | 3 |"tech_2"|
+----------+--------------+--------+
| 6 | ... | ... |
+----------+--------------+--------+
| 7 | ... | ... |
最后,如你所想,
Item-Attribute table 将每行列出一个属性值
+----------+--------------+-------+
| item_id | attribute_id | value |
+----------+-----------+----------+
| 1 | 2 | 1 |
+----------+--------------+-------+
| 1 | 2 | 3 |
+----------+--------------+-------+
Meaning that item 1, for attribute 2 (`memory`), has values 1 and 3 (`ddr2` and `ddr3`)
这将涵盖您的所有条件:
- 属性个数不限,随心所欲,不固定
- 你可以明确定义什么类别有什么属性
- 两个类别可以具有相同的属性
- 如果 1 件商品属于具有相同属性的两个类别,您可以只显示一个(即
SELECT * from Category-Attribute where category_id in (SELECT category_id from ItemCategories where item_id = ...)
将为您提供符合条件的属性列表,即使 2 个类别具有相同的属性,每个类别也只有一个
- 你可以做一个
rank
,我想我没有足够的信息来进行这个查询,但是作为一个完全规范化的模型,你肯定可以做一个排名。您在这里几乎拥有完整的模型,因此您肯定可以找出查询。
这与 Magento 使用的模型非常相似。它非常强大,但当然,它可能会变得难以管理,但如果我们想要保持模型严格并确保它将强制执行约束并接受所有 SQL 函数,这是最好的方法.
对于不太严格的系统,选择具有更灵活模式的 NoSQL
数据库始终是一个选择。
我有三个实体,项目、类别和属性。
一个Item
可以是一个或多个Categories
,所以有N:M关系
Item ItemCategories Categories
id name item_id category_id id name
1 alfa 1 1 1 chipset
1 2 2 interface
一个 Item
可以有多个 Attributes
,具体取决于它们所在的 'Categories'。
例如,Category
'chipset' 中的项目可以具有以下属性:'interface'、'memory' 'tech'.
这些属性有一组不经常更改的预定义值,但它们可以更改。
例如:'memory'只能是ddr2,ddr3,ddr4.
Attributes CategoryAttributes
id name values category_id attribute_id
1 memory {ddr2, ddr3, ddr4} 1 1
'chipset' Category
中的 Item
可以访问 Attribute
并且只能具有 Null 或属性的预定义值。
我想使用 Enum
或 Json
作为属性值,但我还有另外两个条件:
项目属性
item_id attribute_id value
1 1 {ddr2, ddr4}
1) 如果一个Attribute出现在2个Categories中,一个Ithe同时出现在两个Categories中,一个属性只能显示一次。
2) 我需要使用rank
的值,所以如果一个项目出现两个对应的属性值,如果只有一个,则排名应该更大,或者该值不存在。
3)为属性创建单独的表不是一种选择,因为数量不固定,而且可能很大。
所以,我不知道数据库设计中的最佳选择是限制值并用于订单排名。
您所描述的问题是一个典型的开放模式或垂直数据库,这是某种 EAV
模型的经典用例。
EAV 是一个复杂而强大的范例,它允许潜在的开放模式,同时尊重 database normal forms 并允许拥有您需要的东西:根据同一实体的特定实例拥有可变数量的属性。
这就是使用关系数据库的电子商务中通常会发生的情况,因为不同的产品具有不同的属性(例如口红有颜色,但对于硬盘驱动器,您可能不关心颜色而是容量)而且它不具有一个属性 table 是有意义的,因为数字不固定并且可以很大,并且对于大多数行,会有很多 NULL
值(这是稀疏矩阵的数学概念,在数据库中看起来很丑 table)
您可以看一下 Magento DB Model, a true reference in pure EAV at scale, or Wikipedia,但您可能稍后再做,现在,您只需要基础知识:
基本思想是在单个 table.
中将属性及其对应值存储为行而不是列在更简单的实现中,table 至少有三列:entity
(通常是实体的外键,或实体 type/category),attribute
(这可以是一个字符串,o 在更复杂的系统中是一个外键)和 value
。
在我之前的示例中,过于简单化了,我们可以有一个像这样的 table,它列出了
的属性名称及其值Item table Attributes table
+------+--------------+ +-------------+-----------+-------------+
| id | name | | item_id | attribute | value |
+------+--------------+ +-------------+-----------+-------------+
| 1 | "hard drive" | | 2 | "color" | "red" |
+------+--------------+ +-------------+-----------+-------------+
| 2 | "lipstick" | | 2 | "price" | 10 |
+------+--------------+ +-------------+-----------+-------------+
| 1 | "capacity"| "1TB" |
+-------------+-----------+-------------+
| 1 | "price" | 200 |
+-------------+-----------+-------------+
So for every item, you can have a list of attributes.
由于你的模型比较复杂,约束也比较多,所以我们需要适配这个模型。
- 由于您想限制可能的值,因此您需要 table 值
- 因为你会有一个值table,这些值必须引用一个属性,所以你需要属性有一个id,所以你会有一个属性table
- 为了明确和严格什么类别有什么属性,你需要一个类别属性table
有了这个,你最终会得到类似
的东西类别table 类别 ID 和名称列表
+------+--------------+
| id | name |
+------+--------------+
| 1 | "chipset" |
+------+--------------+
| 2 | "interface" |
+------+--------------+
属性table 属性 ID 列表及其名称
+------+--------------+
| id | name |
+------+--------------+
| 1 | "interface" |
+------+--------------+
| 2 | "memory" |
+------+--------------+
| 3 | "tech" |
+------+--------------+
| 4 | "price" |
+------+--------------+
类别-属性table 什么类别有什么属性。请注意,一个属性(即 4)可以属于 2 个类别
+--------------+--------------+
| attribute_id | category_id |
+--------------+--------------+
| 1 | 1 |
+--------------+--------------+
| 2 | 1 |
+--------------+--------------+
| 3 | 1 |
+--------------+--------------+
| 4 | 1 |
+--------------+--------------+
| 4 | 2 |
+--------------+--------------+
值table 每个属性的可能值列表
+----------+--------------+--------+
| value_id | attribute_id | value |
+-------------+-----------+--------+
| 1 | 2 | "ddr2" |
+----------+--------------+--------+
| 2 | 2 | "ddr3" |
+----------+--------------+--------+
| 3 | 2 | "ddr4" |
+----------+--------------+--------+
| 4 | 3 |"tech_1"|
+----------+--------------+--------+
| 5 | 3 |"tech_2"|
+----------+--------------+--------+
| 6 | ... | ... |
+----------+--------------+--------+
| 7 | ... | ... |
最后,如你所想,
Item-Attribute table 将每行列出一个属性值
+----------+--------------+-------+
| item_id | attribute_id | value |
+----------+-----------+----------+
| 1 | 2 | 1 |
+----------+--------------+-------+
| 1 | 2 | 3 |
+----------+--------------+-------+
Meaning that item 1, for attribute 2 (`memory`), has values 1 and 3 (`ddr2` and `ddr3`)
这将涵盖您的所有条件:
- 属性个数不限,随心所欲,不固定
- 你可以明确定义什么类别有什么属性
- 两个类别可以具有相同的属性
- 如果 1 件商品属于具有相同属性的两个类别,您可以只显示一个(即
SELECT * from Category-Attribute where category_id in (SELECT category_id from ItemCategories where item_id = ...)
将为您提供符合条件的属性列表,即使 2 个类别具有相同的属性,每个类别也只有一个 - 你可以做一个
rank
,我想我没有足够的信息来进行这个查询,但是作为一个完全规范化的模型,你肯定可以做一个排名。您在这里几乎拥有完整的模型,因此您肯定可以找出查询。
这与 Magento 使用的模型非常相似。它非常强大,但当然,它可能会变得难以管理,但如果我们想要保持模型严格并确保它将强制执行约束并接受所有 SQL 函数,这是最好的方法.
对于不太严格的系统,选择具有更灵活模式的 NoSQL
数据库始终是一个选择。