从长远来看,创建SQL表以便轻松查询的最佳方法是什么?

时间:2014-08-20 07:08:44

标签: php mysql sql database database-design

我目前正在为客户开展一个项目。他的需求发生了变化,因此我的数据库结构也必须改变。

我的客户经营旅行社业务,他每天都会注册很多人。他想要实现的是能够将乘客分组。因此,在管理界面中,您单击要分组的乘客,瞧。他们是一群人。

在每个小组中,您可以分配额外费用,例如午餐,饮料,租用装备,以便工作人员可以将价格映射到该组。

以下是我需要的,我的问题是如何从中构建SQL表。我目前正在阅读一对多的关系,外键等。从长远来看,我希望能够毫无问题地查询数据库,在我过去的经历中有很多问题:

Groups
gp_ID    customer_ID    leader    fare_Type    dependant_Fare_Child    dependant_Fare_Adult

Tour_Extras
TE_ID    TE_Name

Tour_Extra_Price
TE_ID    TE_Price    fare_ID

Fare_Type
fare_ID    fare_Name

Group_Extras
gp_ID    TE_ID    quantity    fare_ID

包含该组中的所有乘客。只有一个领导者,customer_ID将用作该乘客所有联系人的另一个表的参考。 fare_Type将是一个引用Fare_Type表的int。 dependant_Fare_Ch和成人也是整数。这将决定以成人价格收取的儿童和儿童被分配给受抚养人的人数。

Tour_Extras 持有附加组可以拥有的类型。例如午餐,装备租赁

Tour_Extra_Price 保留特定额外费用和fare_ID,这将决定收取什么价格(儿童,成人,老年人)

Fare_Type 持有fare_Id和名字(儿童,成人,高级)

Group_Extras 这是重要的。它将引用组,tour_extra和可能的Fare_Type表。这将用于确定该特定组的总金额。例如:

gp_ID TE_ID quantity fare_ID
  1     1      3       1

对于ID为1的群组,他们选择了TE_ID为1(例如午餐)和购买数量(3),并将收取费用为fare_ID 1(例如儿童)

这可能对某些人有所帮助:

Tour_Extras可以有很多Tour_Extra_Price

Tour_Extra_Price可以有一个Fare_Type

Group_Extras可以有很多Group,Tour_Extras和/或Fare_Type(不确定是直接与Fare_Type链接,还是通过Tour_Extras,然后是Tour_Extra_Price,然后是Fare_Type)

我还有其他问题需要外键吗?是否最好在Group_Extras表上使用主键,在其他表上使用外键?

长篇大论道歉,但我想在完成这个项目之前用尽所有选项并进行研究。

p.s我不会再回来几个小时了。所以请问问题,我会在12小时内回答。

2 个答案:

答案 0 :(得分:1)

您的数据库结构通常可以满足您所描述的要求。 我建议您添加一个“组”表,您可以将其用于为组成员共享的公共属性,例如ID,必要时组的名称或时间戳。你也可以直接在这里设置领导者的ID,而不是在group表的每一行中都有一个“leader”标志。

除此之外,我会做出一个改变;因为您使用的是MySQL,所以您可以选择使用ENUM字段作为fareType而不是Fare_Type表(因为我假设3个值不太可能改变 - 如果它们发生变化,您可以轻松添加更多值)。这样可以简化您的查询,因为您必须少做一次连接,并且还可以使您的数据库在调试时更具可读性。在学术上你的解决方案是正确的,我只是改变这一点,使你的生活更轻松(并使数据库更具可读性)。当然,如果用户想要编辑fareTypes本身,则必须将其保存为单独的表格。

从技术上讲,您不需要任何外键 - 如果您只添加主键并在更新/删除/插入逻辑中记住关系,那么您的应用程序将正常工作。如果添加外键,它将在表上添加约束,以便不会违反其完整性。例如。如果要删除Tour_Extra,首先必须确保没有其他表有引用,否则会出现约束错误。虽然事情有所改善,但我并不是真的很想在MySQL中使用外键,过去常常遇到很多问题。如果您选择使用它们,则无论如何都需要将表设置为InnoDB数据库引擎。

您的主键应该非常明确:

  
      
  • 群组 - > gp_ID(auto_increment)
  •   
  • 群组 - > gp_ID,customer_ID
  •   
  • Tour_Extras - > TE_ID(auto_increment)
  •   
  • Tour_Extra_Price - > TE_ID,fareType(枚举)
  •   
  • Group_Extras - > gp_ID TE_ID,fareType(枚举)
  •   

外键,如果你选择分配它们:

  
      
  • 群组 - > gp_ID引用Group.gp_ID,customer_ID引用customer.customer_ID
  •   
  • Tour_Extra_Price - > TE_ID引用Tour_Extra.TE_ID
  •   
  • Group_Extras - > gp_ID引用Group.gp_ID,(TE_ID,fareType)引用(Tour_Extra_Price.TE_ID,Tour_Extra_Price.fareType)
  •   

答案 1 :(得分:1)

显然,我们相隔几个小时,所以请求评论部分的问答回合花费了太多时间。因此,不是每天提出更多的问题,而是我的想法:

首先:customer_id实际代表什么?您是否存储了客户,以便在他们反复预订旅行时识别他们?对我来说这似乎并不是这样(无论如何,你会从中获得什么?)。从我看来,它看起来更像是一次预订给我。因此,每当米勒先生预订旅游时,他都会得到一个新的customer_id。但如果是这样,customer_id不代表他的完整预订吗?你不需要米勒夫人的customer_id,因为她将被包含在预订中。

所以我看到的是预订。这包括一个人的姓名和联系方式(我的例子中的米勒先生)以及旅行者人数。那将是:

表格预订

  • booking_id
  • tour_id
  • 名称
  • 地址
  • 电话

table booking_passengers

  • booking_id
  • fare_type_id (成人/儿童/老年人)
  • 数量(预订中该类型的数量

数据应始终位于表中,而不是表名或列名中。所以你不会有像dependant_Fare_Child和dependant_Fare_Adult这样的列,而是一个带有fare_id列的表booking_passengers,所以你可以根据ID加入。

因此预订(或您称之为客户)已经代表一个团体。您是否需要有关共同乘客的更多详细信息,然后将booking_passengers替换为每位乘客保留一条记录的表格:

table booking_passenger

  • booking_id
  • fare_type_id (成人/儿童/老年人)
  • 名称
  • 年龄

你的巡演演出结构看起来不错。当我打电话给您的客户或团体预订时,我的表格将是:

表格预订_extras

  • booking_id
  • tour_extra_id (午餐/齿轮/ ......)
  • fare_type_id (成人/儿童/老年人)

对于旅游价格,我假设这样一张桌子,顺便说一句:

table tour_price

  • tour_id
  • fare_type_id (成人/儿童/老年人)

上表中的主键是斜体。你应该使用外键。存在它们以保证数据一致性,例如没有预订就没有乘客。数据库人员总是认为在关系数据库中有外键并且在数据一致性和可用索引方面存在同样多的关系。所以表booking_extras将有一个主键booking_id + tour_extra_id + fare_type_id。您可以通过booking_id预订表格的外键,通过tour_extra_id预订tour_extra,通过fare_type_id预订fare_type。

希望这会有所帮助。如果我误解了任何内容,请在评论中告诉我,我希望有时间相应地调整我的答案。