mysql - 在数据库模式设计方面需要帮助以获取打印厂产品选项

标签 mysql database database-design activerecord

我最近一直在打印店网站上工作。而且我现在在开发有效的数据库模式方面遇到了麻烦。

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

喜欢,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”海报是没有意义的。海报产品将有自己的尺寸。价格始终与期权组合绑定(bind),没有期权组合的产品没有单独的价格。

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

请提供一些关于设计这样一个数据库的见解。我也想要一种基于 ActiveRecord 的方法,因为我在 EAV 建模方面太弱了。

最佳答案

你可以这样做:

Products :

  • ProductId主键,
  • ProductName ,
  • ...

  • Materials :
  • MaterialID主键,
  • MaterialName .

  • Units :
  • UnitId主键,
  • UnitName .

  • ProductsSizesOptions :
  • SizeOptionId主键,
  • Height ,
  • Width ,
  • UnitId外键约束 REFERENCES Units(UnitId)为每种产品处理不同类型的单元。

  • ProductsMaterialOptions :
  • MaterialOptionId ,
  • Quantity ,
  • MaterialId外键约束 REFERENCES Materials(MaterialId)为每种产品的报价处理不同类型的 Material 。

  • ProductsOffers :
  • OfferId主键,
  • ProductId外键约束 REFERENCES Products(ProductId) ,
  • MaterialOptionId外键约束 REFERENCES ProductsMaterialOptions(MaterialOptionId)`,
  • SizeOptionId外键约束 REFERENCES ProductsSizesOptions(SizeOptionId) ,
  • Price .

  • enter image description here

    例如,对于您在问题中发布的示例数据,您可以通过 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;
    

    这会给你类似的东西:
    | 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 |
    

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

    SQL Fiddle Demo For DB schema

    更新

    Products :
  • ProductId ,
  • ProductName ,
  • ...

  • Options :
  • OptionId ,
  • OptionName .

  • 要存储可能的选项:
    OptionId OptionName
    1 Material
    2 Shape
    and so on
    

    Properties :
  • PropertyId ,
  • PropertyName ,
  • PropertyTypeId .

  • PropertiesTypes :
  • PropertyTypeId ,
  • PropertyTypeName .

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

    OptionsProperties :
  • OptionPropertyId ,
  • OptionId ,
  • PropertyId .

  • 每个选项的属性,例如 ShapeMaterial :
    OptionPropertyId OptionId PropertyId 
    1                   1        1
    2                   2        2
    3                   2        3
    4                   2        4
    

    ProductOptions :
  • ProductOptionId ,
  • ProductId ,
  • OptionId .

  • ProductOptionsValues :
  • ProductOfferOptionsId ,
  • ProductId ,
  • PropertyId ,
  • NumericValue ,
  • TXTValue .

  • ProductsOffers :
  • OfferId ,
  • ProductOfferOptionsId ,
  • Quantity ,
  • Price .

  • enter image description here

    因此您可以获得每个产品的报价列表,如下所示:
    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;
    

    这会给你:
    |   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 |
    

    SQL Fiddle Demo

    当然,这个查询没有意义。要获取所有属性的列表,您必须使用动态 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;
    

    Updated SQL Fiddle Demo

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

    关于mysql - 在数据库模式设计方面需要帮助以获取打印厂产品选项,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15631807/

    相关文章:

    包含意外值的 PHP 对象属性

    mysql - Navicat 添加字段到现有表

    mysql - 在 MySQL 中创建表

    php - 如何使用 PHP INSERT 将数组存储到 mysql 并使用相同的 id 变量值

    sql-server - SQL Server 中的最大数据库名称长度

    SQL - 用于将事物列表与行相关联的设计

    php - 可捕获的错误 - 参数必须是 PDO 的实例

    mysql - 哪个更好 : storing string including Unicode characters in NVARCHAR or VARCHAR?

    Mysql外键

    mysql - 我有一个子表,它依赖于两个不相关的父表。我想将行插入子表中