认为添加此内容很重要,因为当您看到问题时,我认为答案并不完整。原始问题已得到很好的回答,但这里有一个小故障。所以我只考虑下面引用的附加问题:
另一件事是他想在付款表中包含总金额,我认为这是不必要的(只需计算产品的单价和数量即可。)。他指出,我们需要该列来计算对整个系统管理至关重要的借方和/或贷方,它是平衡交易所必需的。请告诉我你的想法。
这个编辑很有趣。基于这是一个处理金钱的交易系统的事实,它必须负责。我采用一些基本术语:交易、产品、价格、金额。
从这个意义上说,它非常普遍,甚至需要非规范化。为什么?因为你需要它负责。因此,当事务被注册时,它可能永远不会被修改。如果您需要更正它,那么您将进行另一笔交易。
现在是的,您可以计算例如产品价格 * 金额 * 税金等。这在标准化意义上是有意义的。但是,您将需要完全锁定所有相关记录。以 products 表为例:如果您在交易前更改价格,则应在交易发生时将其考虑在内。但如果之后价格发生变化,则不会影响交易。
因此,仅加入 transaction.product_id=products.id 是不可接受的,因为该产品可能会发生变化。例子:
2012-01-01 price = 10
2012-01-05 price = 20
Transaction happens here, we sell 10 items so 10 * 20 = 200
2012-01-06 price = 22
现在我们在 2012-01-10 查找交易,所以我们这样做:
SELECT
transactions.amount * products.price AS totalAmount
FROM transactions
INNER JOIN products on products.id=transactions.product_id
那将给出 10 * 22 = 220 所以这是不正确的。
所以你有2个选择:
不允许更新产品表。因此,您对该表进行了版本控制,因此对于每条记录,您都添加了一个新的 INSERT 而不是更新。所以交易一直指向产品的正确版本。
或者您只需将字段添加到事务表中。因此,将 totalAmount 添加到 transactions 表并在插入事务时计算它(在数据库事务中)并保存。
是的,它是非规范化的,但它有充分的理由,它让它负责。您只知道并通过交易、锁等验证了交易发生的那一刻,它与所描述的产品相关,价格 = 20 等。
除此之外,当您无论如何都必须这样做时,这只是非规范化的一件好事,运行报告非常容易。月、年等总交易金额,计算起来非常简单。
规范化有很多好处,例如没有双重存储、单点编辑等。但在这种情况下,您只是不想要这个概念,因为对于事务日志数据库来说,这是不允许的,也不首选的。
将交易视为对现实世界中发生的事情的登记。它发生了,你把它写下来。现在你不能改变历史,它是按原样写的。未来不会改变它,它发生了。