我希望这个标题有点帮助。我正在使用MySQL作为我的数据库
我正在构建产品数据库,我不知道如何处理产品变化的存储价格/ SKU。产品可能具有无限的变化,每种变化组合都有自己的价格/ SKU /等。
这就是我现在设置我的产品/变体表格的方式:
PRODUCTS
+--------------------------+
| id | name | description |
+----+------+--------------+
| 1 | rug | a cool rug |
| 2 | cup | a coffee cup |
+----+------+--------------+
PRODUCT_VARIANTS
+----+------------+----------+-----------+
| id | product_id | variant | value |
+----+------------+----------+-----------+
| 1 | 1 | color | red |
| 2 | 1 | color | blue |
| 3 | 1 | color | green |
| 4 | 1 | material | wool |
| 5 | 1 | material | polyester |
| 6 | 2 | size | small |
| 7 | 2 | size | medium |
| 8 | 2 | size | large |
+----+------------+----------+-----------+
(`products.id` is a foreign key of `product_variants.product_id`)
我使用此示例数据创建了一个SQLFiddle:http://sqlfiddle.com/#!2/2264d/1
允许用户输入任何变体名称(product_variants.variant
),并可以为其分配任何值(product_variants.value
)。 用户可能无法限制变化/值。
这就是我出现问题的地方:每次有人添加一个以前不存在的变体的产品时,不会添加新的表/列,为每个变体存储价格/ SKU。
每个变体可能具有相同的价格,但SKU对每个产品都是唯一的。
例如,产品1
有6种不同的组合(3种颜色* 2种材料),而产品2
只有3种不同的组合(3种尺寸* 1)。
我考虑过将这些组合存储为文本,即:
+------------+-----------------+-------+------+
| product_id | combination | price | SKU |
+------------+-----------------+-------+------+
| 1 | red-wool | 50.00 | A121 |
| 1 | red-polyester | 50.00 | A122 |
| 1 | blue-wool | 50.00 | A123 |
| 1 | blue-polyester | 50.00 | A124 |
| 1 | green-wool | 50.00 | A125 |
| 1 | green-polyester | 50.00 | A125 |
| 2 | small | 4.00 | CD12 |
| 2 | medium | 4.00 | CD13 |
| 2 | large | 3.50 | CD14 |
+------------+-----------------+-------+------+
但必须有更好的,规范化的方式来表示这些数据。假设情况:我希望能够搜索低于10美元的蓝色产品。使用上面的数据库结构,如果不解析文本就不可能做到这一点,这是我想要避免的。
感谢任何帮助/建议=)
答案 0 :(得分:33)
对您的问题应用规范化,解决方案如下所示。在Fiddle上运行并查看它
CREATE TABLE products
(
product_id int auto_increment primary key,
name varchar(20),
description varchar(30)
);
INSERT INTO products
(name, description)
VALUES
('Rug', 'A cool rug' ),
('Cup', 'A coffee cup');
create table variants (variant_id int auto_increment primary key,
variant varchar(50)
);
insert into variants (variant)
values ('color'),('material'),('size') ;
create table variant_value(value_id int auto_increment primary key,
variant_id int ,
value varchar(50)
);
insert into variant_value (variant_id,value)
values (1 ,'red'),(1 ,'blue'),(1 ,'green'),
(2 ,'wool'),(2 ,'polyester'),
(3 ,'small'),(3 ,'medium'),(3 ,'large');
create table product_Variants( product_Variants_id int auto_increment primary key,
product_id int,
productVariantName varchar(50),
sku varchar(50),
price float
);
create table product_details(product_detail_id int auto_increment primary key,
product_Variants_id int,
value_id int
);
insert into product_Variants(product_id,productVariantName,sku,price)
values (1,'red-wool' ,'a121',50);
insert into product_details(product_Variants_id , value_id)
values( 1,1),(1,4);
insert into product_Variants(product_id,productVariantName,sku,price)
values (1,'red-polyester' ,'a122',50);
insert into product_details(product_Variants_id , value_id)
values( 2,1),(2,5);
答案 1 :(得分:16)
您的部分问题源于产品与SKU之间的混淆。
当您销售时," XYZ套衫,尺码M,蓝色型号",后者对应SKU。它作为XYZ套衫(产品)销售,它具有一组属性(大小和颜色),每个属性都有自己的一组潜在值。并非后者的所有可能组合都可能产生有效的可交付成果:你不会找到荒谬的薄牛仔裤。 SKU,产品,属性,属性值。
当用户想要10美元的蓝色套头衫时,他实际上在产品类别中寻找SKU。
我希望上述内容可以解决您的困惑以及您的问题和问题源于何处。
就架构而言,您需要以下内容:
或者,也可以添加:
这是营销相关表格。没有其他的。如果营销之外的任何在您的应用程序中使用了某个产品,那么您将会陷入一个痛苦的世界。
价格(如果存在)是用于在SKU中为空时填充该字段的主要价格。这使得价格输入更加用户友好。
in_stock是一个有希望的自我解释的旗帜,理想情况下由触发器维持。如果与该产品相关的任何 SKU都有库存,则应该是真的。
这只包含颜色,大小等等,以及蓝色,红色,S,M,L等值。
请注意product_id字段:为每个产品创建一组新的属性和值。尺寸根据产品而变化。有时它是S,M,L等;其他时候,它将是38,40,42,什么不是。有时候,尺寸就足够了;其他时候,你需要宽度和长度。蓝色可能是该产品的有效颜色;另一个可能会提供海军,皇家蓝,蓝绿色等等。不要认为某个产品的属性与另一个产品的属性之间存在任何关系;它们存在时的相似之处完全是装饰性的和巧合的。
(可选)添加:
这相当于发货的可交付成果。
它实际上是下面最重要的表格。 此,而不是product_id,几乎可以肯定应该在客户订单中引用。它也应该被引用到库存等等。 (我在后两点看到的唯一例外是当你卖出一些非常通用的东西。但即便如此,根据我的经验来处理这个问题的更好方法是在可互换的SKU之间投入一个nm关系。)
如果添加名称字段,则主要是为了方便起见。如果保留为null,请使用应用程序端代码使其与通用产品的名称相对应,必要时使用相关的属性名称和值进行扩展。填充它允许用更自然的东西(" Levis' 501)重新描述后一个通用名称(" Levis' 501,W:32,L:32,颜色:深蓝") ,32x32,深蓝色")。
如果重要的话,从长远来看,使用触发器可以更好地维护库存,并在后台使用复式簿记架构。这样就可以在您遇到的大量真实场景中区分现货和今天可用的货物(这是您实际需要的数字)与库存但已售出的数量。哦,而且......如果您需要出售以千克或升为单位的任何东西,它偶尔会是数字而不是整数。如果是这样,请务必添加额外的is_int标志,以避免客户向您发送.1笔记本电脑的订单。
为了生成默认名称,这会将可交付物的ID与相应的属性和值相关联。
主键开启(sku_id,attribute_id)。
您可能会发现product_id字段存在异常。除非你添加引用的外键:
(如果您决定添加这些外键,请不要忘记相应元组上的额外唯一索引。)
最后还有三个评论。
首先,我想再次强调,就流量而言,并非所有属性和值的组合都会产生有效的可交付成果。宽度可能是28-42,长度可能是28-42,但你可能不会看到一条严重的28x42紧身牛仔裤。您最好不要默认自动填充每个产品的每个可能的变体:添加UI以根据需要启用/禁用它们,默认情况下选中它,以及名称,条形码和价格字段。 (名称和价格通常会留空;但有一天,您只需要在蓝色套头衫上进行销售,理由是颜色已停止,而您继续销售其他选项。)
其次,请记住,如果您需要另外管理产品选项,那么许多实际上是伪装的产品属性,并且那些不会产生新SKU的东西在必要时也必须考虑在内到库存。例如,用于笔记本电脑的更大HD选项实际上是由于(非常有效的)UI考虑而伪装成选项的相同产品(正常与大HD尺寸)的变体。相比之下,将笔记本电脑作为圣诞礼物包装是一个真正的选择,它在记账条款中引用了完全独立的SKU(例如.8m的礼品包装) - 并且,如果您需要提出平均边际成本,那么工作人员的时间。
最后,您需要为您的属性,值以及后续变体提供排序方法。为此,最简单的方法是在属性和值表中添加一个额外的位置字段。
答案 2 :(得分:5)
我会使用4个表:
generic_product: product_id, name, description
e.g。 1,'地毯','咖啡地毯'/ 2,'马克杯','咖啡杯'
generic_product_property: product_id, property_id, property_name
e.g。 1,10,'颜色'/ 1,11''材料'
sellable_product: sku, product_id, price
e.g。 'A121',1,50.00 /'A122',1,45.00
sellable_product_property: sku, property_id, property_value
e.g。 'A121',10,'red'/'A121',11,'wool'/'A122',10,'green'/'A122',11,'wool'
这将允许您的用户为您想要的可销售产品定义任何属性。
您的应用程序必须确保其业务逻辑完全描述sellable_products(检查每个适用的通用产品属性是否定义了可销售产品属性)。
答案 3 :(得分:1)
这类似于我在SO
上看到的另一个问题Designing a database : Which is the better approach?
如果你看看那里,你会发现你基本上要求相同的狭窄(基于属性)和宽表问题。我根据场景使用了两者,但我现在非常小心你实现它的方式。事实上,没有一种方法可以将这些变体与SKU相匹配(至少不是我能想到的)可能会迫使你改变你的表格。
如果你有这么多不同的变种,你也可能想要查看键值数据库或其他一些NoSQL解决方案。
答案 4 :(得分:1)
一般而言,您正在寻找所谓的石斑鱼或垃圾维度。基本上它只是每一个组合的一行。@ sahalMoidu的架构看起来应该给你你所要求的。
但是在关注规范化之前,你需要知道数据库是否用于存储数据(事务性等)或用于获取数据(维度,报告等)。即使它是一个事务性数据库,您也必须问自己,您要通过规范化来完成什么。
答案 5 :(得分:0)
Sku是您的主要钥匙。您可以使用sku设置变量表的外键关系。完全忘掉productid。
创建表x(sku,价格,描述)主键sku