【问题标题】:DB schema, many-many or bool values in table表中的数据库模式、多对多或布尔值
【发布时间】:2012-03-19 20:29:11
【问题描述】:

如果我的数据库中有很多餐厅,并且每个餐厅都可以有午餐菜单、晚餐菜单或早午餐菜单,那么在餐厅表中使用布尔值是否有意义:

餐厅编号 |餐厅名称 |地址 |等等。 |午餐菜单 |晚餐菜单 |早午餐菜单

或者我应该创建一个菜单表,然后有一个 RestaurantMenu 表(多对多关系)

菜单 ID |菜单名称

1 |午餐菜单

2 |晚餐菜单

3 |早午餐菜单

【问题讨论】:

  • 如果只有 3 个菜单栏有 bool 类型,则无需创建另一个表
  • 那么,一家餐厅可以有超过 1 个菜单,还是只提供这 3 个菜单之一?
  • 老实说,这个问题的答案取决于您是否认为需要将其他菜单类型添加到数据库中。如果您确定涵盖了所有类型,那么拥有bool 列将非常易于使用和查询。但如果非要加一个意外的话,可能会很头疼。我提供了两个答案,展示了我用于扩展性的几种方法。

标签: mysql database database-schema


【解决方案1】:

另一个建议是使用链接器表。这将更易于维护且易于记录。当您具有多对多关系时,将使用链接器表。 (一家餐厅可以有多种类型的菜单,并且许多餐厅都可以使用一种特定类型的菜单。)

这使您可以稍后在“menu_types”表中将其他菜单类型添加为一行,而无需更改任何表的结构。

不过,它确实使您的查询更加复杂,因为您必须执行一些连接。

首先,您将拥有三个类似这样的表:

restaurants
---------------
id    name
1     Moe's
2     Steak & Shrimp House
3     McDonald's

restaurant_menus
----------------
restaurant_id    menu_type
1                1
1                3
2                4
3                1
3                3
3                4

menu_types
---------------
id    type
1     Breakfast
2     Brunch
3     Lunch
4     Dinner

因此,要查看每家餐厅提供的菜单类型,您的查询如下:

SELECT r.name, mt.type
FROM restaurants r
    JOIN restaurant_menus rm
        ON (r.id = rm.restaurant_id)
    JOIN menu_types mt
        ON (rm.menu_type = mt.id)
ORDER BY r.name ASC;

这会产生:

name                  type       
--------------------  -----------
McDonald's            Lunch      
McDonald's            Breakfast  
McDonald's            Dinner     
Moe's                 Breakfast  
Moe's                 Lunch      
Steak & Shrimp House  Dinner     

【讨论】:

  • 您好,感谢您的精彩回答。现在我正在为一个 iphone 应用程序实现这个,并且我正在使用 HTTP GET。以下是我正在使用的 SQL 查询,但它不包含连接。这是否足够有效? "SELECT menu_name FROM Menus WHERE menu_id IN (SELECT menus_id FROM Restaurants_Menus WHERE Restaurants_id = '$restaurantID')"
  • 我想说这是一个关于 SQL 查询效率的新问题。但总的来说,以我的经验,子查询并不是很有效;这取决于您对索引的实现和其他因素。
【解决方案2】:

我的建议是使用简单的位掩码类型的字段:

例如:

1 = breakfast
2 = brunch
4 = lunch
8 = dinner

如果有必要,您可以添加更多。

如果一家餐厅同时提供早餐和午餐,但没有早午餐和晚餐,则为 1+4,因此该列得到 5。

如果一家餐厅具备以上所有条件,那就是 1+2+4+8,也就是 15。

然而,对于未来的数据库维护者来说,它可能不是最易读的。但是,用一列表示多个选项是一种简单的方法。

编辑:

这只是简单的二进制操作。它的工作原理是这样的:

Dinner   Lunch   Brunch   Breakfast
-------- ------- -------- ---------
0        0       0        1             1 (Breakfast only)
1        1       0        0             12 (Dinner + Lunch)
1        1       1        1             15 (All four)

这种字段的优点是您可以在不更改数据库的情况下添加其他菜单类型,假设您的 int 字段存储了足够的位。

在您的程序中,您可以通过一些位运算符确定哪些类型的菜单可用。在 C# 中,例如:

const int BREAKFAST = 1;
const int BRUNCH = 2;
const int LUNCH = 4;
const int DINNER = 8;

int RestaurantMenuType = 5;

bool OffsersBreakfastMenu = (RestaurantMenuType & BREAKFAST) == BREAKFAST;
bool OffsersBrunchMenu = (RestaurantMenuType & BRUNCH) == BRUNCH;
bool OffsersLunchMenu = (RestaurantMenuType & LUNCH) == LUNCH;
bool OffersDinnerMenu = (RestaurantMenuType & DINNER) == DINNER;

Console.WriteLine("Offers breakfast? {0}", OffsersBreakfastMenu ? "Yes" : "No");
Console.WriteLine("Offers brunch? {0}", OffsersBrunchMenu ? "Yes" : "No");
Console.WriteLine("Offers lunch? {0}", OffsersLunchMenu ? "Yes" : "No");
Console.WriteLine("Offers dinner? {0}", OffersDinnerMenu ? "Yes" : "No");

【讨论】:

  • 但是如果你有4,你将如何区分3+1?我想你的意思是2^X,对吧?
  • BUt 比 1 + 3 = 4 和 4 也是晚餐。所以你需要 0 - 没有菜单,1 - 早餐,2 - 早午餐,4 - 午餐,8 - 晚餐 (2^n)
  • 我从一个伪造的二进制应用程序开始,然后编辑了答案。我为此道歉,我没有在精神上正确地转换事情。值应为 1、2、4、8 等,而不是 1、2、3、4 等。
  • 这很有帮助,但对我的需求来说是不必要的。此时我的数据库非常简单,因此您在上面给出的解决方案似乎更实用。不过这很有趣。
猜你喜欢
  • 2022-10-19
  • 2019-02-15
  • 2023-04-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-24
  • 2010-09-20
相关资源
最近更新 更多