库存管理与库存选项

时间:2014-01-09 01:49:04

标签: mysql database database-design schema relational-database

我正在尝试创建库存管理架构,以便跟踪与产品相关的各种选项的库存。产品可能有任意数量的选项,但对于此示例,我将使用“尺寸”和“颜色”选项。

我想出了三张桌子:

CREATE TABLE shop_options (
  option_id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
  option_name VARCHAR(40) NOT NULL,

  PRIMARY KEY (option_id)
);
INSERT INTO shop_options (option_id, option_name) VALUES (1, 'Size');
INSERT INTO shop_options (option_id, option_name) VALUES (2, 'Color');

CREATE TABLE shop_option_properties (
  prop_id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
  prop_name VARCHAR(40) NOT NULL,

  PRIMARY KEY (prop_id)
);
INSERT INTO shop_option_values (prop_id, prop_name) VALUES (1, 'XS');
INSERT INTO shop_option_values (prop_id, prop_name) VALUES (2, 'S');
INSERT INTO shop_option_values (prop_id, prop_name) VALUES (3, 'M');
INSERT INTO shop_option_values (prop_id, prop_name) VALUES (4, 'L');
INSERT INTO shop_option_values (prop_id, prop_name) VALUES (5, 'XL');
INSERT INTO shop_option_values (prop_id, prop_name) VALUES (6, 'White');
INSERT INTO shop_option_values (prop_id, prop_name) VALUES (7, 'Black');
INSERT INTO shop_option_values (prop_id, prop_name) VALUES (8, 'Red');
INSERT INTO shop_option_values (prop_id, prop_name) VALUES (9, 'Green');
INSERT INTO shop_option_values (prop_id, prop_name) VALUES (10, 'Blue');

CREATE TABLE shop_product_options (
  product_id INTEGER UNSIGNED NOT NULL,
  option_id INTEGER UNSIGNED NOT NULL,
  prop_id INTEGER UNSIGNED DEFAULT NULL,
  surcharge DECIMAL(7,2) NOT NULL DEFAULT '0.00',
  stock INTEGER UNSIGNED DEFAULT NULL, /* NULL = stock is not limited */

  FOREIGN KEY (product_id)
    REFERENCES shop_products(product_id),
  FOREIGN KEY (option_id)
    REFERENCES shop_options(option_id),
  FOREIGN KEY (prop_id)
    REFERENCES shop_option_properties(prop_id)
);

我已经确定这不起作用,因为我的库存中可能有“十件小件物品”,库存中有“十件白色物件”,但库存中没有“十件小白件”。 / p>

如何改进我的架构以正确跟踪产品可能具有的每个选项的库存?

修改


我将以下更新包含在其他任何与此相同的问题中。我发现接受的答案起初很难理解。基本上,我可以在shop_product_options表上保留上面的模式并进行以下修改:

CREATE TABLE shop_product_options (
  po_id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
  product_id INTEGER UNSIGNED NOT NULL,
  option_id INTEGER UNSIGNED NOT NULL,
  prop_id INTEGER UNSIGNED NOT NULL,
  surcharge DECIMAL(7,2) UNSIGNED NOT NULL DEFAULT '0.00',
  stock INTEGER UNSIGNED DEFAULT NULL,

  PRIMARY KEY (po_id, product_id, option_id, prop_id),
  FOREIGN KEY (product_id)
    REFERENCES shop_products(product_id),
  FOREIGN KEY (option_id)
    REFERENCES shop_options(option_id),
  FOREIGN KEY (prop_id)
    REFERENCES shop_option_properties(prop_id)
);

使用添加的po_id和组合键作为主键,我现在可以按如下方式插入和提取“分组”数据:

INSERT INTO shop_products (product_id, title) VALUES (1, 'Womens Shoe');

INSERT INTO shop_product_options (po_id, product_id, option_id, prop_id, surcharge, stock)
  VALUES (1, 1, 1, 3, '0.00', 10);
INSERT INTO shop_product_options (po_id, product_id, option_id, prop_id, surcharge, stock)
  VALUES (1, 1, 2, 9, '0.50', 20);
INSERT INTO shop_product_options (po_id, product_id, option_id, prop_id, surcharge, stock)
  VALUES (2, 1, 1, 5, '1.00', 30);
INSERT INTO shop_product_options (po_id, product_id, option_id, prop_id, surcharge, stock)
  VALUES (2, 1, 2, 9, '0.75', 40);

SELECT t1.po_id, t2.title, t3.option_name, t4.prop_name, t1.surcharge, t1.stock FROM shop_product_options AS t1
  JOIN shop_products AS t2 ON t1.product_id = t2.product_id
  JOIN shop_options AS t3 ON t1.option_id = t3.option_id
  JOIN shop_option_properties AS t4 ON t1.prop_id = t4.prop_id
WHERE t1.product_id = 1 ORDER BY t1.po_id ASC;

这样就形成了一款M尺寸的绿色女式鞋,以及尺寸为XL的绿色女式鞋,每种尺寸和颜色都有不同的库存数量。

2 个答案:

答案 0 :(得分:5)

我认为草稿模型(following 6NF 和3NF )会对您有所帮助。
我通过删除'shop'关键字简化了命名约定 (商店实体也可以引导单独的概念AKA SaaS)

SqlFiddle Demo

enter image description here

关于评论中的问题:

  

是否可以拥有唯一的产品ID

是的,在您的表格上使用surrogate identifier是一种常见模式。正如您在文章中看到的那样,这将带来它的优点和缺点。

例如,在问题中,您会看到ProductSpecification表的主键是ProductTypeOptionsOptionValueProduct外键的组合。
在其他表格(如OptionValue)的平均时间主键是复合键(OptionId + ValueName
看起来生活将更容易在每个表中都有一个ID字段作为主键,是的,但是作为数据库设计者,您将放弃一些有价值的东西,业务逻辑

在当前设计中,您可以在Product-Specification表中使用这些约束,它们将显示您的业务逻辑的一部分:

  • 检查ProductSpecification {OptionValue.optionId = productTypeOption.optionId}上的约束,该约束会阻止像“白色”这样的值 被分配到“大小”。
  • 检查ProductSpecification {product.productTypeId = productTypeOption.productTypeId}上的约束,这会阻止类似的产品 “Nike”被分配到“汽车”的产品规格。

如果使用代理标识符,则不能在数据库中使用这些类型的约束(尝试此操作) 在您的应用程序实现中需要做额外的工作才能获得它们 BTW use surrogate identifier, check data consistency,如果您有兴趣,请参阅choosing a Primary Key: Natural or Surrogate

  

基本价格,库存和附加费应该在哪里?

似乎“耐克”的“男士鞋”需要有价格,库存和附加费,因此它们是Product表的自然属性。

答案 1 :(得分:0)

这是让你入门的东西......

每个独特类型的项目都应该拥有自己的SKU(请看示例4),这样您就可以像这样设计数据库:

colors
    id              unsigned int(P)
    description     varchar(10)

+----+-------------+
| id | description |
+----+-------------+
|  1 | White       |
|  2 | Blue        |
|  3 | Green       |
| .. | ........... |
+----+-------------+

items
    id              unsigned int(P)
    description     varchar(20)

+----+-------------+
| id | description |
+----+-------------+
|  1 | T-shirt     |
|  2 | Pencil      |
| .. | ........... |
+----+-------------+

sizes
    id              unsigned int(P)
    description     varchar(10)

+----+-------------+
| id | description |
+----+-------------+
|  1 | Small       |
|  2 | Medium      |
|  3 | Large       |
| .. | ........... |
+----+-------------+

在我的示例数据中,SKU S1C1I1是一件白色小T恤,S2C3I1是中号绿色T恤。

products
    id              unsigned int(P)
    sku             varchar(50)
    price           double
    quantity        unsigned int

+----+--------+-------+----------+
| id | sku    | price | quantity |
+----+--------+-------+----------+
|  1 | S1C1I1 | 10.00 |      312 |
|  2 | S2C3I1 | 11.00 |       52 |
| .. | ...... | ..... | ........ |
+----+--------+-------+----------+

您的产品表中也可能包含UPC,EAN等。