我一直在做一个项目,当我遇到一个设计难题时,我认为这是非常常见的情况。请告诉我你是怎么处理的。让我们假设我们正在为一家商店构建一个网络应用程序。有一个目录表,有许多行,例如
ID |名称|价格
- |玩具车|10$
- |泰迪熊|2$
以及带有付款方式的订单表。我应该如何存储有关订单详细信息的数据,即购买的产品?主要关注的是如何处理目录表中的更改,如价格修改。
我想出的解决方案是:
-
有一个结构类似于catalog的表order_details,并且与orders表有多对一关系。当用户购买某物时,必要的数据会从目录表复制到order_details表。这需要大的存储空间,因为我们复制所有(或至少部分)列,并且在catalogs表中修改列的情况下,需要将更改传播到order_detals。
-
另一个想法是利用缓慢改变维度的机制(来自数据仓库)。目录表需要额外的列,如:
ID|名称|价格|版本
-
|玩具车|10$|1
-
|泰迪熊|2$|1
-
|泰迪熊|4$|2
和order_details表,与orders表有多对一关系,与catalogs表有很多对一关系。在这种情况下,order_details表中的行数相同,但列数较少。这种方法的缺点是需要管理产品的版本。
这里有一个类似问题的答案,它讨论的是Version Normal Form.
您需要将价格(以及您想要跟踪的任何其他数据)标准化到一个单独的表中。您的FK将继续正常工作。你所要做的就是得到订单发出时有效的价格。这有点棘手,但并不难。
通常,数据库设计取决于商店应用程序逻辑。但我猜这种方法会对你有所帮助:
在中创建表catalog_prices (priceId, productId, price, date)
目录表将price
列更改为priceId
。所以每个产品都将有一个当前价格,catalog_prices表将有产品价格历史记录。因此,查询
SELECT c.ID, c.name, p.price FROM catalogs AS c
INNER JOIN catalog_prices AS p ON c.priceId = p.priceId
将返回所有带有价格的产品并查询
SELECT c.ID, c.name, p.price, p.date FROM catalogs AS c
INNER JOIN catalog_prices AS p ON c.ID = p.productId
将返回所有价格历史记录。
接下来,在order_details
表中添加productPriceId
列。所以查询
SELECT d.ID, d.orderId, c.name, p.price FROM order_details AS d
INNER JOIN catalog_prices AS p ON p.priceId = d.productPriceId
INNER JOIN catalogs AS c ON p.productId = c.ID
将返回订单详细信息和价格。
此解决方案将添加用于显示目录产品和订购产品的附加联接,但允许减少数据重复—价格将存储在一个位置。您将能够看到产品价格历史记录。