我最近一直在Print Shop网站上工作。而我现在在开发高效的数据库架构方面遇到了麻烦。
我的应用程序是一个Printshop,提供海报,名片和传单等自定义打印。 我面临的问题是开发产品选项的架构。 这是一个场景: 名片可以有“尺寸”和“材料”选项。 “尺寸”可以是“3.5x2.5英寸”或“3.25x2.25英寸”。类似地,“材料”可以是“300gsm卡片库存”或“200gsm卡片库存”。 现在我的商店提供的是期权和数量组合的价格。
像,
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建模方面太弱了。
答案 0 :(得分:3)
你可以这样做:
<强> Products
强>:
ProductId
主键,ProductName
, <强> Materials
强>:
MaterialID
主键,MaterialName
。 <强> Units
强>:
UnitId
主键,UnitName
。 <强> ProductsSizesOptions
强>:
SizeOptionId
主键,Height
,Width
,UnitId
外键约束REFERENCES Units(UnitId)
,用于处理每种产品的不同类型的单位。 <强> ProductsMaterialOptions
强>:
MaterialOptionId
,Quantity
,MaterialId
外键约束REFERENCES Materials(MaterialId)
,用于处理每种产品的不同类型的材料。 <强> ProductsOffers
强>:
OfferId
主键,ProductId
外键约束REFERENCES Products(ProductId)
,MaterialOptionId
外键约束REFERENCES 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;
这会给你类似的东西:
| 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 |
然后,从您的前端应用程序,您可以按照您希望的方式格式化这些结果。
<强> 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
。每个选项的属性,例如Shape
和Material
:
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
。
这样您就可以获得每种产品的优惠清单:
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动态执行此操作。您可以将以下代码放在存储过程中:
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;
这将动态地旋转所有属性。
答案 1 :(得分:2)
您正在销售目录中的商品。项目可以是Good(实际上是产品的规格而不是实物资产),也可以是商品集合,称为营销包。
您需要在此处使用Table Inheritance。
catalog_item
------------
id
type {good, marketing_package}
name
good : catalog_item
-------------------
size
material
marketing_package : catalog_item
--------------------------------
standard_price
marketing_package_good (this is a junction table)
----------------------
marketing_package_id
good_id
quantity
poster : good
-------------
{any poster-specific properties or defaults}
flyer : good
------------
{any flyer-specific properties or defaults}
business_card : good
--------------------
{any business-card-specific properties or defaults}