【问题标题】:Best way to store working hours and query it efficiently存储工作时间并有效查询的最佳方式
【发布时间】:2011-05-26 18:43:08
【问题描述】:

我打算存储商店的工作时间。我想知道工作时间字段的最佳建模是什么,以便我可以非常有效地获取当前打开/关闭的商店列表。

【问题讨论】:

    标签: sql mysql database database-design


    【解决方案1】:

    要存储正常营业时间,您需要存储一些记录,其中包含:

    • 商店 - INTEGER
    • DayOfWeek - 整数 (0-6)
    • 开放时间 - 时间
    • 关闭时间 - 时间

    我假设例如每个商店在国定假日期间减少了工作时间,或者工厂停工,因此您还需要存储一些覆盖记录:

    • 商店 - INTEGER
    • OverrideStartDate - 日期
    • 覆盖结束日期 - 日期
    • DayOfWeek - 整数 (0-6)
    • AltOpenTime - 时间
    • AltCloseTime - 时间
    • 关闭 - INTEGER (0, 1)

    找到营业的商店很简单,但您还需要检查是否有覆盖时间:

    SELECT Shop
    FROM OverrideHours
    WHERE OverrideStartDate <= NOW()
    AND OverrideEndDate >= NOW()
    AND DayOfWeek = WEEKDAY(NOW())
    

    如果有任何记录返回,这些商店有交替营业时间或关闭。

    您可以在这里执行一些不错的 SQL-fu,但这为您提供了基础知识。

    编辑

    我没有对此进行测试,但这应该会让你接近:

    SELECT Normal.Shop
    FROM Normal
    LEFT JOIN Override
    ON Normal.Shop = Override.Shop
    AND Normal.DayOfWeek = Override.DayOfWeek
    AND NOW() BETWEEN Override.OverrideStartDate AND Override.OverrideEndDate
    WHERE Normal.DayOfWeek = WEEKDAY(NOW())
    AND ((Override.Shop IS NULL AND TIME(NOW()) BETWEEN Normal.OpenTime AND Normal.CloseTime)
     OR  (Override.Shop IS NOT NULL AND Override.Closed <> 1 AND TIME(NOW()) BETWEEN Override.AltOpenTime AND Override.AltCloseTime))
    

    编辑

    至于效率,它是高效的,因为您只需调用一次 MySQL,如果它是跨网络的,这通常是一个瓶颈。您必须测试并查看这是否符合您的规格。如果没有,你可能会玩一些索引。

    编辑

    测试。未完成测试,但有一些。

    mysql> select * from Normal;
    +------+-----------+----------+-----------+
    | Shop | DayOfWeek | OpenTime | CloseTime |
    +------+-----------+----------+-----------+
    |    1 |         1 | 09:00:00 | 17:00:00  | 
    |    1 |         5 | 09:00:00 | 16:00:00  | 
    |    2 |         1 | 09:00:00 | 17:00:00  | 
    |    2 |         5 | 09:00:00 | 17:00:00  | 
    +------+-----------+----------+-----------+
    4 rows in set (0.01 sec)
    
    mysql> select * from Override;
    +------+-------------------+-----------------+-----------+-------------+--------------+--------+
    | Shop | OverrideStartDate | OverrideEndDate | DayOfWeek | AltOpenTime | AltCloseTime | Closed |
    +------+-------------------+-----------------+-----------+-------------+--------------+--------+
    |    2 | 2010-12-01        | 2010-12-31      |         1 | 09:00:00    | 18:00:00     |      0 | 
    |    2 | 2010-12-01        | 2010-12-31      |         5 | 09:00:00    | 18:00:00     |      0 | 
    |    1 | 2010-12-01        | 2010-12-31      |         1 | 09:00:00    | 17:00:00     |      1 | 
    +------+-------------------+-----------------+-----------+-------------+--------------+--------+
    3 rows in set (0.00 sec)
    
    mysql> SET @whenever = TIMESTAMP('2010-11-23 16:05');
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> SELECT WEEKDAY(@whenever);
    +--------------------+
    | WEEKDAY(@whenever) |
    +--------------------+
    |                  1 | 
    +--------------------+
    1 row in set (0.00 sec)
    
    mysql> SELECT Normal.Shop FROM Normal LEFT JOIN Override ON Normal.Shop = Override.Shop AND Normal.DayOfWeek = Override.DayOfWeek AND @whenever BETWEEN Override.OverrideStartDate AND Override.OverrideEndDate WHERE Normal.DayOfWeek = WEEKDAY(@whenever) AND ((Override.Shop IS NULL AND TIME(@whenever) BETWEEN Normal.OpenTime AND Normal.CloseTime)  OR  (Override.Shop IS NOT NULL AND Override.Closed <> 1 AND TIME(@whenever) BETWEEN Override.AltOpenTime AND Override.AltCloseTime));
    +------+
    | Shop |
    +------+
    |    1 | 
    |    2 | 
    +------+
    2 rows in set (0.00 sec)
    
    mysql> SET @whenever = TIMESTAMP('2010-11-23 17:05');
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> SELECT Normal.Shop FROM Normal LEFT JOIN Override ON Normal.Shop = Override.Shop AND Normal.DayOfWeek = Override.DayOfWeek AND @whenever BETWEEN Override.OverrideStartDate AND Override.OverrideEndDate WHERE Normal.DayOfWeek = WEEKDAY(@whenever) AND ((Override.Shop IS NULL AND TIME(@whenever) BETWEEN Normal.OpenTime AND Normal.CloseTime)  OR  (Override.Shop IS NOT NULL AND Override.Closed <> 1 AND TIME(@whenever) BETWEEN Override.AltOpenTime AND Override.AltCloseTime));
    Empty set (0.01 sec)
    
    mysql> SET @whenever = TIMESTAMP('2010-12-25 16:05');
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> SELECT Normal.Shop FROM Normal LEFT JOIN Override ON Normal.Shop = Override.Shop AND Normal.DayOfWeek = Override.DayOfWeek AND @whenever BETWEEN Override.OverrideStartDate AND Override.OverrideEndDate WHERE Normal.DayOfWeek = WEEKDAY(@whenever) AND ((Override.Shop IS NULL AND TIME(@whenever) BETWEEN Normal.OpenTime AND Normal.CloseTime)  OR  (Override.Shop IS NOT NULL AND Override.Closed <> 1 AND TIME(@whenever) BETWEEN Override.AltOpenTime AND Override.AltCloseTime));
    +------+
    | Shop |
    +------+
    |    2 | 
    +------+
    1 row in set (0.00 sec)
    
    mysql> SET @whenever = TIMESTAMP('2010-11-23 17:05');
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> SELECT WEEKDAY(@whenever);
    +--------------------+
    | WEEKDAY(@whenever) |
    +--------------------+
    |                  1 | 
    +--------------------+
    1 row in set (0.00 sec)
    
    mysql> SELECT Normal.Shop FROM Normal LEFT JOIN Override ON Normal.Shop = Override.Shop AND Normal.DayOfWeek = Override.DayOfWeek AND @whenever BETWEEN Override.OverrideStartDate AND Override.OverrideEndDate WHERE Normal.DayOfWeek = WEEKDAY(@whenever) AND ((Override.Shop IS NULL AND TIME(@whenever) BETWEEN Normal.OpenTime AND Normal.CloseTime)  OR  (Override.Shop IS NOT NULL AND Override.Closed <> 1 AND TIME(@whenever) BETWEEN Override.AltOpenTime AND Override.AltCloseTime));
    Empty set (0.00 sec)
    

    【讨论】:

    • 很好的答案!快速提问:在ShopDayOfWeekOpenTimeCloseTime 上放置索引是否可取?
    • @RabidFire,请参阅stackoverflow.com/questions/3049283/… 的答案。如果您正在寻找的主要效率是查询(例如,与插入相反),那么向 WHERE 或 JOIN ON 中使用的任何字段添加索引应该会加快搜索速度。您必须进行测试,看看哪个最有效。
    • @Antoniossss,您每天可以输入多个条目... 第 1 天 17:00-11:59:59,第 2 天 00:00-3:00,第 2 天 17:00-11 :59:59,第 3 天 00:00-3:00 等...您的代码必须满足每天输入多个时间的要求。或者,根据您的需要,您可能需要开发不同的模型。
    • @RobertGowland 你能告诉你AltOpenTimeAltCloseTime 是什么意思吗? Someone need to know it :)
    • @Sami 和 @Belle ,“每个商店在国定假日期间减少了工作时间,或者工厂停工”,这就是 Override 表的目的。列名中的“alt”确实代表“alternative”。从查询中可以看出,如果Override 表中有条目,则使用该表中的小时数。
    【解决方案2】:

    假设每周的所有营业时间都相同。那么下表呢:

    • shop_id - INTEGER(或商店的任何唯一标识符)
    • week_day - INTEGER(0=星期一 - 6=星期日)
    • opens_at - TIME(使用您当地的时区)
    • closes_at - TIME(使用您当地的时区)

    shop_id标识的店铺制作一张表格,然后插入营业时间,即:

    • 1、0、8:00、17:00
    • ...
    • 1、5、8:00、12:00
    • 2、0、7:30、12:30
    • 2、0、13:30、17:30
    • 2、1、7:30、12:30
    • 2、1、13:30、17:30
    • ...

    然后选择:

    SELECT shop_id
    FROM opening_hours
    WHERE WEEKDAY(NOW()) = week_day
    AND TIME(NOW()) BETWEEN opens_at AND closes_at
    

    【讨论】:

      猜你喜欢
      • 2015-05-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-28
      • 2020-10-25
      • 2012-07-15
      • 2013-08-22
      • 2016-06-06
      相关资源
      最近更新 更多