【问题标题】:One to Many relashionships for a restaurants website?餐厅网站的一对多关系?
【发布时间】:2010-05-29 03:00:28
【问题描述】:

每家餐厅都有分店,每家分店都必须确定它在一周中的哪几天营业,每一天都必须确定(几个)open_hour 和 close_hour 到那一天。

我使用这些表创建了一对多关系: rest_names ---> rest_branches ---> open_days ---> open_hours

我要往这边走吗?或者还有另一种方法可以做到这一点,也许不那么复杂? 以及查询将如何获取特定日期(例如星期天)的餐厅营业时间?

【问题讨论】:

  • 非常感谢您的精彩回答,也感谢 Daniel 的建议。 :)

标签: database data-modeling


【解决方案1】:

我建议先存储营业时间,然后存储每家餐厅的营业时间,而不是关闭时间。这样可以更轻松地计算营业时间,也可以避免与午夜后营业的餐厅产生歧义。

示例设计,使用 MySQL:

CREATE TABLE restaurant_chains (
    id int AUTO_INCREMENT PRIMARY KEY,
    name varchar(20)
);

CREATE TABLE restaurant_branches (
    id int AUTO_INCREMENT PRIMARY KEY,
    chain_id int NOT NULL,
    locality varchar(20)
);

CREATE TABLE opening_times (
    id int AUTO_INCREMENT PRIMARY KEY,
    branch_id int NOT NULL,
    day_of_week int NOT NULL,
    open_time time,
    open_duration time
);

确保添加相关的外键和唯一约束。您还可以添加一个检查约束,以便 day_of_week 始终介于 1 和 7 之间,因为这将代表工作日(1 代表星期日,2 代表星期一,等等)。

现在让我们用一些测试数据填充我们的数据库:

INSERT INTO restaurant_chains VALUES (NULL, 'Chain A');
INSERT INTO restaurant_chains VALUES (NULL, 'Chain B');

INSERT INTO restaurant_branches VALUES (NULL, 1, 'Branch 1 for A');
INSERT INTO restaurant_branches VALUES (NULL, 1, 'Branch 2 for A');
INSERT INTO restaurant_branches VALUES (NULL, 2, 'Branch 1 for B');
INSERT INTO restaurant_branches VALUES (NULL, 2, 'Branch 2 for B');

INSERT INTO opening_times VALUES (NULL, 1, 1, '10:00:00', '04:00:00');
INSERT INTO opening_times VALUES (NULL, 1, 1, '19:00:00', '03:00:00');
INSERT INTO opening_times VALUES (NULL, 1, 2, '08:00:00', '12:30:00');
INSERT INTO opening_times VALUES (NULL, 2, 1, '19:00:00', '05:15:00');
INSERT INTO opening_times VALUES (NULL, 2, 2, '19:00:00', '04:00:00');

以下查询返回所有餐厅的营业时间、关闭时间和持续时间:

SELECT  rb.locality,
        ot.day_of_week,
        ot.open_time,
        ADDTIME(ot.open_time, open_duration) AS close_time,
        ot.open_duration
FROM    opening_times ot
JOIN    restaurant_branches rb ON (rb.id = ot.branch_id)
JOIN    restaurant_chains rc ON (rc.id = rb.chain_id);

+----------------+-------------+-----------+------------+---------------+
| locality       | day_of_week | open_time | close_time | open_duration |
+----------------+-------------+-----------+------------+---------------+
| Branch 1 for A |           1 | 10:00:00  | 14:00:00   | 04:00:00      | 
| Branch 1 for A |           1 | 19:00:00  | 22:00:00   | 03:00:00      | 
| Branch 1 for A |           2 | 08:00:00  | 20:30:00   | 12:30:00      | 
| Branch 2 for A |           1 | 19:00:00  | 24:15:00   | 05:15:00      | 
| Branch 2 for A |           2 | 19:00:00  | 23:00:00   | 04:00:00      | 
+----------------+-------------+-----------+------------+---------------+
5 rows in set (0.00 sec)

然后以下查询将返回特定餐厅在特定日期的营业时间:

SELECT  ot.open_time,
        DATEADD(ot.open_time, open_duration) AS close_time,
        ot.open_duration
FROM    opening_times ot
JOIN    restaurant_branches rb ON (rb.id = ot.branch_id)
JOIN    restaurant_chains rc ON (rc.id = rb.chain_id)
WHERE   rb.id = 1 AND ot.day_of_week = 1;

+-----------+------------+---------------+
| open_time | close_time | open_duration |
+-----------+------------+---------------+
| 10:00:00  | 14:00:00   | 04:00:00      | 
| 19:00:00  | 22:00:00   | 02:00:00      | 
+-----------+------------+---------------+
2 rows in set (0.00 sec)

【讨论】:

  • 哇。这怎么不是公认的答案?就是想。 :)
【解决方案2】:

一个餐厅名称到许多分店
许多分支机构到许多开放日
许多开放日到许多开放时间

选择[列名]
来自 open_days
在 open_days.rest_branchId = rest_branches.rest_branchId
上加入 rest_branches 在 rest_name 上加入 rest_name.rest_nameId = rest_branch
其中 open_days = '星期天'

【讨论】:

    【解决方案3】:

    这取决于您存储开放日的方式(我假设您使用的是日期值),但只要 DBMS 的数据类型支持,您可以将日期和时间组合在一个列中。这样就不必将“open_hours”加入“open_days”。

    【讨论】:

      【解决方案4】:

      您走在正确的道路上。我看到的实体是:

      • 连锁餐厅(例如 TGI Friday's)
      • 餐厅(具体一家);
      • 营业时间(餐厅、日期、营业时间、关闭时间)

      一天有一个实体似乎没有必要。

      【讨论】:

      • 我认为你用表名切换了列名。营业时间(餐厅、日期、营业时间、关闭时间)
      • 此外,此模型仅在每周同一天的营业时间相同的假设下有效。
      • @DVK 通常是这种情况。但是,如果您想更具体,可以使用日期而不是日期。
      【解决方案5】:

      从数据模型设计来看,在链和分支的表中,不一定要将 ID 列作为主键:您可能必须为其他列定义唯一约束(例如链名称,例如),并且该列可能完全是主键。 ID 列将是代理键,您可以决定是否拥有它。有些人认为始终拥有这样的主键是一种很好的做法,但这并不是绝对必要的。你甚至会发现在很多情况下它不值得拥有。

      【讨论】:

        【解决方案6】:

        您可以考虑将餐厅名称、星期几和营业时间放在一张桌子上。
        例如。 Freds Diner/星期一/10.00/22.00/星期二/11.00/21.00/等 在您派出规范化警察之前,请注意在此结构中保持完整的完整性。在可预见的未来,任何人都不太可能创造一周中的新一天。
        关于是否使用此结构的考虑与以编程方式访问/读取/更新信息的难易程度有关。 如果需要,您还可以在同一行中包含餐厅地址。 笔记。 “地址”是一种属性类型 - 本身不是属性。它和 DATE 一样是 COMPOSITE 属性类型。名称 + 属性类型 = 属性 EG INVOICE + ADDRESS = 发票地址和 INVOICE + DATE = 发票日期。发票地址和发票日期都是单一的复合属性并遵循相同的规则。 关于数据结构的主要问题是数据完整性——规范化只是一种尝试确保数据完整性的方法。

        【讨论】:

          猜你喜欢
          • 2011-01-05
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2010-09-30
          • 1970-01-01
          • 1970-01-01
          • 2023-03-15
          相关资源
          最近更新 更多