考虑假期和特殊情况的工作时间的数据库设计

时间:2015-04-14 15:29:04

标签: database date database-design

我在stackoverflow上看到了一些关于如何设计数据库表来存储营业时间的例子,但它们并没有满足我的所有需求。他们不支持根据一年中的周期来定义不同的小时数,也不支持假期和一年中的特殊时间可以关闭。

我的需求

  • 支持重叠2天的营业时间。例如,一个酒吧可以在下午6点开门,并在凌晨3点关闭
  • 支持同一天的多个开放时间
  • 支持日期已关闭
  • 支持在一段时间内开/关时间不同的不同情况

方案

一般来说,商店#1将有这些营业时间

  • 星期一,上午9点至中午12点和下午1点至5点
  • 星期二,上午9点至下午12点和下午1点至5点
  • 星期三,上​​午9点至下午12点和下午1点至5点
  • 周四,上午9点至中午12点,下午1点至晚上9点
  • 星期五,上午9点到下午12点,下午1点到9点
  • 星期六,上午10点到下午5点
  • 星期天,关闭

在12月份,开放时间不同

  • 星期一,上午9点到下午12点,下午1点到9点
  • 星期二,上午9点至下午12点和下午1点至9点
  • 星期三,上​​午9点至下午12点和下午1点至9点
  • 周四,上午9点至中午12点,下午1点至晚上9点
  • 星期五,上午9点到下午12点,下午1点到9点
  • 星期六,上午10点到下午5点
  • 周日,上午10点至下午5点

他们在这些日期关闭:

  • 12月25日
  • 1月1日

由于某些原因,他们有特殊情况,开放时间可能不同:

  • 7月10日,下午1点至9点
  • 9月20日,下午1点到9点

到目前为止我的解决方案

StoreId  BeginDate   EndDate     DayOfWeek  OpenHour  Duration
1        2015-01-01  2015-11-30  2          09:00     180
1        2015-01-01  2015-11-30  2          13:00     240
1        2015-01-01  2015-11-30  3          09:00     180
1        2015-01-01  2015-11-30  3          13:00     240
...
1        2015-12-01  2015-12-31  2          09:00     180
1        2015-12-01  2015-12-31  2          13:00     480
1        2015-12-01  2015-12-31  3          09:00     180
1        2015-12-01  2015-12-31  3          13:00     480
...

我看到的问题

  • 我不确定BeginDate / EndDate应该在该表中。也许我应该有另一个表来定义Periods并在OpenHours表上有一个链接到句点的外键。
  • 我应该在哪里定义关闭日期(假期)?
  • 我应该在哪里定义开放/关闭时间不同的特殊日期?就像超越定义的内容一样?

3 个答案:

答案 0 :(得分:0)

我会将开放时间存储为RFC 5445 RRules和ExRules。

有些图书馆有functions以英文文本显示规则。

我发现使用Google日历生成RRules和ExRules很容易。

答案 1 :(得分:0)

不要再考虑规则了。想想行。

如果您只是存放营业时间,这很简单。 PostgreSQL对这类事情有特别好的支持。

create table business_hours (
  open tstzrange primary key,
  exclude using gist (open with &&)
);

exclusion constraint保证不会重叠开放时间。如果它每天需要两行,那么一年的数据就会超过700行。 100年的数据只有70k行。这是大多数灵活选项,开发和测试时间几乎为零,最低工资职员可以验证您要宣传的营业时间是否与您打开的时间相匹配。

正常时间

-- The "normal" hours for the week starting Apr 13, 2015 (a Monday).
insert into business_hours values
-- Mon
(tstzrange('2015-04-13 09:00', '2015-04-13 12:00')),
(tstzrange('2015-04-13 13:00', '2015-04-13 17:00')),
-- Tue
(tstzrange('2015-04-14 09:00', '2015-04-14 12:00')),
(tstzrange('2015-04-14 13:00', '2015-04-14 17:00')),
-- Wed
(tstzrange('2015-04-15 09:00', '2015-04-15 12:00')),
(tstzrange('2015-04-15 13:00', '2015-04-15 17:00')),
-- Thu
(tstzrange('2015-04-16 09:00', '2015-04-16 12:00')),
(tstzrange('2015-04-16 13:00', '2015-04-16 21:00')),
-- Fri
(tstzrange('2015-04-17 09:00', '2015-04-17 12:00')),
(tstzrange('2015-04-17 13:00', '2015-04-17 21:00')),
-- Sat
(tstzrange('2015-04-18 10:00', '2015-04-18 17:00'));
-- Sun
-- Closed.

从插入“正常”时间应该可以清楚地看出,这种表格可以容纳任何类型的逻辑,无论好坏。

您可以将这种语句包装在存储的函数中,以便您可以一次生成一周,一个月或一年的“正常”小时。根据需要更新。

在其他dbms中,您可以使用两个时间戳列和一些检查约束。检查重叠行可能必须作为异常报告而不是作为dbms强制执行的约束来完成。

create table business_hours (
  opens timestamp not null,
  closes timestamp not null,
  check (closes > opens),
  primary key (opens, closes)
);

使用这对列作为主键,优化器可以使用仅索引扫描。

答案 2 :(得分:0)

我正在处理同样的问题,到目前为止,我已经为您设计了类似的方法。但是关于你的问题。

  1. 是的,由于#3中的原因,将开始日期和结束日期移至相关表格会有所帮助。
  2. 关闭日期可以是开放时间为null
  3. 默认小时数没有开始和结束日期。所有特殊时间都会定义开始和结束日期。该应用程序查找哪些日期组包括今天的日期。它计算所有组的开始和结束的间隔。最小的间隔获胜。
  4. 顺便说一句,我可能会在一天中按分钟存储我的开放时间,并保留格式以供日后使用...