表版本化(历史表)和订单表关系

时间:2011-10-08 19:47:32

标签: mysql sql database database-design

如果我在products表格中添加新产品或更改数据,它会自动添加到products_history。这是通过触发器完成的。

当客户下订单时,无需在order_products表中复制产品名称。

要从order_products表中获取产品名称和价格,您将从products_history表中查询而不是products

注意:我正在展示简单的演示表。

请参阅下表和结果:

mysql> select * from products;
+----+------------+-------+---------------------+
| id | name       | price | timestamp           |
+----+------------+-------+---------------------+
|  1 | Product 63 |  2.00 | 2011-10-08 18:55:53 |
|  2 | Product 42 |  3.00 | 2011-10-08 18:55:44 |
+----+------------+-------+---------------------+

mysql> select * from products_history;
+----+------------+-------+---------------------+
| id | name       | price | timestamp           |
+----+------------+-------+---------------------+
|  1 | Product 23 |  2.00 | 2011-10-08 18:55:44 |
|  2 | Product 42 |  3.00 | 2011-10-08 18:55:44 |
|  1 | Product 63 |  2.00 | 2011-10-08 18:55:53 |
+----+------------+-------+---------------------+

订单表:

mysql> select * from `order`;
+----+-------------+
| id | total_price |
+----+-------------+
|  1 |     9999.00 |
+----+-------------+

mysql> select * from order_products;
+----+----------+------------+---------------------+
| id | order_id | product_id | product_timestamp   |
+----+----------+------------+---------------------+
|  1 |        1 |          2 | 2011-10-08 18:55:44 |
|  2 |        1 |          1 | 2011-10-08 18:55:53 |
+----+----------+------------+---------------------+

从订单表中获取产品名称和价格:

SELECT order.total_price, products_history. * FROM  `order` 
   LEFT JOIN order_products ON order_products.order_id = order.id
   LEFT JOIN products_history ON products_history.id = order_products.product_id
             AND products_history.timestamp = order_products.product_timestamp
WHERE order.id =1 

结果

+-------------+------+------------+-------+---------------------+
| total_price | id   | name       | price | timestamp           |
+-------------+------+------------+-------+---------------------+
|     9999.00 |    2 | Product 42 |  3.00 | 2011-10-08 18:55:44 |
|     9999.00 |    1 | Product 63 |  2.00 | 2011-10-08 18:55:53 |
+-------------+------+------------+-------+---------------------+

似乎工作正常。

这个设计中是否有任何重大缺陷,或者我可以采取哪些不同的方式?


关于Extras的第二个问题......产品可以有额外的或没有额外的。我是否需要为extra_group表格进行版本化?我只对extra表进行了版本控制。

请参阅下表:

mysql> select * from extra_group;
+----+------------------+
| id | name             |
+----+------------------+
|  1 | Extras Group One |
+----+------------------+

mysql> select * from extras;
+----+---------+-------+---------------------+
| id | name    | price | timestamp           |
+----+---------+-------+---------------------+
|  1 | Extra 1 |  0.30 | 2011-10-08 18:57:55 |
|  2 | Extra 2 |  2.31 | 2011-10-08 18:58:10 |
+----+---------+-------+---------------------+

mysql> select * from extras_history;
+----+---------+-------+---------------------+
| id | name    | price | timestamp           |
+----+---------+-------+---------------------+
|  1 | Extra 1 |  0.30 | 2011-10-08 18:57:55 |
|  2 | Extra 2 |  2.30 | 2011-10-08 18:57:55 |
|  2 | Extra 2 |  2.31 | 2011-10-08 18:58:10 |
+----+---------+-------+---------------------+


mysql> select * from products_extras;
+----+------------+----------------+
| id | product_id | extra_group_id |
+----+------------+----------------+
|  1 |          2 |              1 |
+----+------------+----------------+
//This mean Product ID 2 have extras from  extra_group_id = 1

附加订单表:

mysql> select * from order_products_extras;
+-------------------+----------+---------------------+
| order_products_id | extra_id | extra_timestamp     |
+-------------------+----------+---------------------+
|                 1 |        1 | 2011-10-08 18:57:55 |
|                 1 |        2 | 2011-10-08 18:58:10 |
+-------------------+----------+---------------------+

//客户从product_id 1中选择了extra_id 1和2

使用类似的查询来获取extras_history

中的额外名称和价格

触发器

CREATE TRIGGER `extras-afterinsert` AFTER INSERT ON `extras`
FOR EACH ROW BEGIN
    INSERT INTO `extras_history` VALUES (NEW.`id`, NEW.`name`, NEW.`price`, NEW.`timestamp`);
END
|
CREATE TRIGGER `extras-afterupdate` AFTER UPDATE ON `extras`
FOR EACH ROW BEGIN
    INSERT INTO `extras_history` VALUES (NEW.`id`, NEW.`name`, NEW.`price`, NEW.`timestamp`);
END

products_history表类似。

我是否在浪费时间使用历史表,我是否应该将名称/价格复制到order_productsorder_products_extras表中?

注意:procucts和extras表中将有超过100,000行...每天超过1000个订单。

2 个答案:

答案 0 :(得分:0)

仅记录单个时间戳的一个危险是很难确定给定订单的最新条目。您必须使用子选择或函数。我建议使用start_timestamp和finish_timestamp,后者对于最新的条目为NULL。当一个条目成为历史时,它会填充其finish_timestamp。还有其他方法可以解决这个问题,我确定,但在我看来这是最直接的。

答案 1 :(得分:0)

我真的无法理解你想用历史表来实现什么。如果产品价格快速变化并且您想在当前时间保存产品基价,为什么不将其放入order_product?

orders :
order_id / created_at / status (PK : order_id)

order_products : 
order_id / product_id / quantity /  product_price (PK : order_id, product_id)

这样您就不必每次都加入product_history。你可以为额外的东西做同样的非规范化。

P.S:尽量不要在表/列名中使用“order”之类的保留字,它可能会引入错误。