我想创建一个允许客户从网站订购食物的网站。
有两种食物类型:
如果他们从列表中选择披萨 - 他们可能需要选择Base(薄皮,脱壳),Extras和披萨大小/选项。
如何在这种情况下设计表格?
注意:每个项目都有1个或更多选项。一个选项可能有额外的(1或更多)或没有额外的。如果项目是披萨类型 - 那么它可能有基础(地壳)
看到我试图实现的两个屏幕截图,我在数据库设计的正确路径上或者哪些方面可以做得更好?
关于额外内容,有时我需要为下拉列表添加多个额外内容而不是tickbox。这意味着客户只能从1个,2个或3个下拉菜单中选择1个。
如何设置数据库模式以实现上述自定义选项? 以下是我的想法:
类别表:
+----------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------+--------------+------+-----+---------+----------------+
| cat_id | int(11) | NO | PRI | NULL | auto_increment |
| cat_name | varchar(100) | NO | | NULL | |
+----------+--------------+------+-----+---------+----------------+
项目表:
+-----------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+--------------+------+-----+---------+----------------+
| item_id | int(11) | NO | PRI | NULL | auto_increment |
| cat_id | int(11) | NO | | NULL | |
| item_name | varchar(100) | NO | | NULL | |
| item_type | int(11) | NO | | NULL | |
+-----------+--------------+------+-----+---------+----------------+
- item_type(0 =正常,1 =披萨,2 =套餐)
item_options表:
+-------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+--------------+------+-----+---------+----------------+
| option_id | int(11) | NO | PRI | NULL | auto_increment |
| item_id | int(11) | NO | | NULL | |
| option_name | varchar(100) | NO | | NULL | |
| price | decimal(6,2) | NO | | NULL | |
+-------------+--------------+------+-----+---------+----------------+
item_extras表: (你认为应该有比萨饼托盘和附加品的单独表格吗?)
+-----------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+--------------+------+-----+---------+----------------+
| extra_id | int(11) | NO | PRI | NULL | auto_increment |
| option_id | int(11) | NO | | NULL | |
| name | varchar(50) | NO | | NULL | |
| cost | decimal(6,2) | NO | | NULL | |
+-----------+--------------+------+-----+---------+----------------+
item_pizza_base表:
+-----------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+--------------+------+-----+---------+----------------+
| base_id | int(11) | NO | PRI | NULL | auto_increment |
| option_id | int(11) | NO | | NULL | |
| base_name | varchar(50) | NO | | NULL | |
| cost | decimal(6,2) | NO | | NULL | |
+-----------+--------------+------+-----+---------+----------------+
SQL结果:
mysql> select * from categories;
+--------+----------+
| cat_id | cat_name |
+--------+----------+
| 1 | Pizzas |
| 2 | Burgers |
mysql> select * from items;
+---------+--------+------------------+-----------+
| item_id | cat_id | item_name | item_type |
+---------+--------+------------------+-----------+
| 1 | 1 | Vegetarian Pizza | 1 |
| 2 | 2 | Beef Burger | 0 |
mysql> select * from item_options;
+-----------+---------+-------------+-------+
| option_id | item_id | option_name | price |
+-----------+---------+-------------+-------+
| 1 | 1 | 12 Inches | 5.60 |
| 2 | 1 | 14 Inches | 7.20 |
| 3 | 2 | 1/4lb | 1.80 |
| 4 | 2 | 1/2lb | 2.50 |
mysql> select * from item_extras;
+----------+-----------+-----------+------+
| extra_id | option_id | name | cost |
+----------+-----------+-----------+------+
| 1 | 1 | Mushroom | 1.00 |
| 2 | 1 | Pepperoni | 1.00 |
| 3 | 2 | Mushroom | 1.00 |
| 4 | 2 | Pepperoni | 1.00 |
| 5 | 3 | Chips | 0.50 |
| 6 | 4 | Chips | 0.50 |
正如你可以在1张桌子上看到汉堡包和披萨的额外内容......它应该分开吗?
mysql> select * from item_pizza_base;
+---------+-----------+------------+------+
| base_id | option_id | base_name | cost |
+---------+-----------+------------+------+
| 1 | 1 | Thin Crust | 0.00 |
| 2 | 1 | Deep Crust | 0.00 |
| 3 | 2 | Thin Crust | 0.00 |
| 4 | 2 | Deep Crust | 0.00 |
+---------+-----------+------------+------+
请注意,每件商品的额外费用并不总是相同。例如:比萨尺寸10“每增加1美元,但12英寸比萨增加0.50美元。还有一个案例,每个披萨将有不同的额外费用。
数据库设计是正确的还是可以改进的?
答案 0 :(得分:6)
我坚持使用Extras功能 - 如何为下拉列表设计表格和字段?请参阅我的问题“额外功能(下拉菜单/复选框)”
如果您需要下拉列表,请将下拉列表的值放在表格中 只要您可以轻松地在下拉列表中分离出所需的值,就可以在其中添加额外的值。
Example
table option_labels
-------------------
id integer auto_increment PK
name varchar(40)
table toppings
--------------
id integer auto_increment PK
option_label_id integer foreign key references option_labels(id)
item_id integer foreign key references items(item_id)
price decimal(10,2)
只要您知道该项目,就可以使用以下命令填充下拉列表:
SELECT ol.name, t.price FROM toppings t
INNER JOIN option_labels ol ON (t.option_label_id = ol.id)
WHERE t.item_id = '$item_id'
规范化这些表格
这张表有一个主要缺陷:
mysql> select * from item_extras;
+----------+-----------+-----------+------+
| extra_id | option_id | name | cost |
+----------+-----------+-----------+------+
| 1 | 1 | Mushroom | 1.00 |
| 2 | 1 | Pepperoni | 1.00 |
| 3 | 2 | Mushroom | 1.00 |
| 4 | 2 | Pepperoni | 1.00 |
| 5 | 3 | Chips | 0.50 |
| 6 | 4 | Chips | 0.50 |
+----------+-----------+-----------+------+
它没有标准化,将名称放在单独的标签表中,就像上面的例子一样。如果一行(不包括ID)不唯一,那么您的数据不会正常化并且您做错了。
因为你使用了很多连接,所以最好使用InnoDB,它有一些很酷的功能来加速使用PK的连接。
无论人们怎么说
在缓慢开始之前不要反规范化。
使用索引
在名为* _id的所有字段上添加索引
还要在where
子句中经常使用的alls字段上添加索引
不要将索引放在基数较低的字段上,因此布尔值或枚举字段上没有索引!
索引会减慢插入速度并加快选择速度。
答案 1 :(得分:4)
您有一张订单表。然后是订单商品或订单行表。对于可以含有成分的物品,您最终会得到一个可以容纳成分的桌子。特别是披萨,你必须担心一半,所以人们可以在每一半订购不同的东西。到目前为止,看起来你正朝着正确的方向前进。
我经历设计的方式是先找出“对象”。有些物品,如汉堡或比萨饼,还有无形物品,如订单,订单线。
必胜客拥有在网络上设置披萨的最佳用户界面之一。我会看一下,因为它会给你一些关于如何存储数据的想法。