需要打印店产品选项的数据库架构设计方面的帮助

kha*_*lid 0 mysql database activerecord database-design

我最近一直在制作一家印刷店网站。我现在在开发高效的数据库模式时遇到了麻烦。

我的应用程序是一家印刷店,为海报、名片和传单等提供定制印刷品。我面临的问题是开发产品选项的架构。这是一个场景:名片可以有“尺寸”和“材质”选项。“尺寸”可以是“3.5x2.5 英寸”或“3.25x2.25 英寸”。同样,“材料”可以是“300 gsm 卡片纸”或“200 gsm 卡片纸”。现在我的商店提供的是选项和数量组合的价格。

喜欢, 100 Business Cards + 3.5x2.5 inch + 300 gsm Card Stock = $500.00

或者

200 Business Cards + 3.5x2.5 inch + 300 gsm Card Stock = $800.00

这里需要注意的一点是,“传单”和“海报”产品的“尺寸”选项是不同的。所以“3.5x2.5”的海报没有意义。海报产品将有自己的尺寸。价格始终与期权组合绑定,没有期权组合的产品没有单独的价格。

其次,也有基于重量的运输。所以我也想知道,权重存储在数据库的哪里?

请提供一些有关设计此类数据库的见解。另外,我想要一种基于 ActiveRecord 的方法,因为我在 EAV 建模方面太弱了。

Mah*_*mal 5

你可以这样做:

Products:

  • ProductId首要的关键,
  • ProductName,
  • ...

Materials:

  • MaterialID首要的关键,
  • MaterialName

Units:

  • UnitId首要的关键,
  • UnitName

ProductsSizesOptions:

  • SizeOptionId首要的关键,
  • Height,
  • Width,
  • UnitIdREFERENCES Units(UnitId)用于处理每个产品的不同类型单元的外键约束。

ProductsMaterialOptions:

  • MaterialOptionId,
  • Quantity,
  • MaterialId外键约束REFERENCES Materials(MaterialId)用于处理每种产品报价的不同类型的材料。

ProductsOffers:

  • OfferId首要的关键,
  • ProductId外键约束REFERENCES Products(ProductId)
  • MaterialOptionId外键约束参考 ProductsMaterialOptions(MaterialOptionId)`,
  • SizeOptionId外键约束REFERENCES ProductsSizesOptions(SizeOptionId)
  • Price

在此输入图像描述


例如,对于您在问题中发布的示例数据,您可以通过JOIN表格简单地获取每种产品的这些报价:

SELECT
  po.OfferId,
  p.ProductNAme,
  mo.Quantity,
  m.MaterialName,
  so.Height,
  so.width,
  u.UnitName,
  po.Price
FROM products                      AS p
INNER JOIN ProductsOffers          AS po ON p.ProductId         = po.ProductId
INNER JOIN ProductsMaterialOptions AS mo ON po.MaterialOptionId = mo.MaterialOptionId
INNER JOIN ProductsSizesOptions    AS so ON so.SizeOptionId     = po.SizeOptionId
INNER JOIN Units                   AS u  ON u.UnitId            = so.unitId
INNER JOIN Materials               AS m  ON m.MaterialId        = m.MaterialId;
Run Code Online (Sandbox Code Playgroud)

这会给你类似的东西:

| OFFERID |   PRODUCTNAME | QUANTITY | MATERIALNAME | HEIGHT | WIDTH | UNITNAME | PRICE |
-----------------------------------------------------------------------------------------
|       1 | Business Card |      100 |   Card Stock |      4 |     3 |      gsm |   500 |
|       2 | Business Card |      200 |   Card Stock |      4 |     3 |      gsm |   800 |
Run Code Online (Sandbox Code Playgroud)

然后,从您的前端应用程序中,您可以按照您希望的方式格式化这些结果。

用于数据库模式的 SQL Fiddle 演示


更新

Products:

  • ProductId,
  • ProductName,
  • ...

Options:

  • OptionId,
  • OptionName

存储可能的选项:

OptionId OptionName
1 Material
2 Shape
and so on
Run Code Online (Sandbox Code Playgroud)

Properties:

  • PropertyId,
  • PropertyName,
  • PropertyTypeId

PropertiesTypes:

  • PropertyTypeId,
  • PropertyTypeName

您可能不需要此表,但您可以在前端应用程序中使用它来了解如何在应用程序上显示此字段。例如,它可能包含以下值:

1 Integer
2 String
3 Decimal
...
Run Code Online (Sandbox Code Playgroud)

OptionsProperties:

  • OptionPropertyId,
  • OptionId,
  • PropertyId

每个选项的属性,例如ShapeMaterial

OptionPropertyId OptionId PropertyId 
1                   1        1
2                   2        2
3                   2        3
4                   2        4
Run Code Online (Sandbox Code Playgroud)

ProductOptions:

  • ProductOptionId,
  • ProductId,
  • OptionId

ProductOptionsValues:

  • ProductOfferOptionsId,
  • ProductId,
  • PropertyId,
  • NumericValue,
  • TXTValue

ProductsOffers:

  • OfferId,
  • ProductOfferOptionsId,
  • Quantity,
  • Price

在此输入图像描述

这样您就可以获得每种产品的报价列表,如下所示:

SELECT
  p.ProductName,
  MAX(CASE WHEN pr.PropertyName = 'Material Name' THEN PropertyValue END) AS 'Material Name',
  MAX(CASE WHEN pr.PropertyName = 'Height' THEN PropertyValue END) AS 'Height',
  MAX(CASE WHEN pr.PropertyName = 'Width' THEN PropertyValue END) AS 'Width',
  MAX(CASE WHEN pr.PropertyName = 'Unit' THEN PropertyValue END) AS 'Unit',
  o.Quantity,
  o.Price
FROM products AS p
INNER JOIN
(
  SELECT 
    ProductId,
    PropertyId,
    ProductOfferOptionsId, 
    COALESCE(NumericValue, TXTValue) AS PropertyValue
  FROM 
  ProductOptionsValues
) AS ov ON ov.ProductId = p.ProductId
INNER JOIN OptionsProperties AS op ON op.PropertyId            = ov.PropertyId
INNER JOIN Properties        AS pr ON op.PropertyId            = pr.PropertyId
INNER JOIN ProductsOffers    AS o  ON o.ProductOfferOptionsId  = ov.ProductOfferOptionsId 
GROUP BY p.ProductName,
         o.Quantity,
         o.Price;
Run Code Online (Sandbox Code Playgroud)

这会给你:

|   PRODUCTNAME |  MATERIAL NAME | HEIGHT | WIDTH | UNIT | QUANTITY | PRICE |
-----------------------------------------------------------------------------
| Business Card | gsm Card Stock |    3.5 |   2.5 | inch |      100 |   500 |
| Business Card | gsm Card Stock |    3.5 |   2.5 | inch |      200 |   800 |
Run Code Online (Sandbox Code Playgroud)

SQL 小提琴演示


当然,这个询问是没有意义的。要获取所有属性的列表,您必须使用动态 SQL 动态执行此操作。您可以将以下代码放入存储过程中:

SET @sql = NULL;
SELECT
  GROUP_CONCAT(DISTINCT CONCAT('MAX(IF(pr.PropertyName = ''',
      pr.PropertyName, ''', ov.PropertyValue, 0)) AS ', '''',   pr.PropertyName , '''')
  ) INTO @sql
FROM Properties        AS pr 
INNER JOIN
(
  SELECT 
    PropertyId,
    COALESCE(NumericValue, TXTValue) AS PropertyValue
  FROM 
  ProductOptionsValues
) AS ov ON pr.PropertyId = ov.PropertyId;

SET @sql = CONCAT('SELECT
  p.ProductName, ', @sql , ', o.Quantity,
  o.Price
FROM products AS p
INNER JOIN
(
  SELECT 
    ProductId,
    PropertyId,
    ProductOfferOptionsId, 
    COALESCE(NumericValue, TXTValue) AS PropertyValue
  FROM 
  ProductOptionsValues
) AS ov ON ov.ProductId = p.ProductId
INNER JOIN OptionsProperties AS op ON op.PropertyId            = ov.PropertyId
INNER JOIN Properties        AS pr ON op.PropertyId            = pr.PropertyId
INNER JOIN ProductsOffers    AS o  ON o.ProductOfferOptionsId  = ov.ProductOfferOptionsId 
GROUP BY   p.ProductName,
  o.Quantity,
  o.Price');



prepare stmt 
FROM @sql;

execute stmt;
Run Code Online (Sandbox Code Playgroud)

更新的 SQL Fiddle 演示

这将动态地旋转所有属性。