我正在设计一个 postgres 表来记录每周计划中包含的间隔。它会保存多个企业的时间表,一个简单的示例数据集可能如下所示:
business_id interval
----------- -----------------------------------
1 Sunday 10:00:00 – Sunday 14:00:00
1 Sunday 22:00:00 – Monday 02:00:00
1 Friday 11:00:00 – Friday 16:00:00
1 Saturday 15:00:00 – Sunday 01:00:00
请注意,间隔可以跨越日期之间的界限。
一个企业不应该有重叠的时间间隔,我想以一种可以让我强制执行的方式设计表格。
我正在考虑将这些星期几 + 一天中的时间值映射到自一周开始以来的相应秒数,将间隔存储为int4range
并使用排除约束来禁止重叠的整数范围,但这并不合适地址间隔围绕周末结束。
有没有一种好的方法可以对这种周期性数据进行建模并禁止重叠?
将每个星期几 + 时间值映射到自间隔开始的一周开始以来的相应秒数,将间隔存储在一
int4range
列中,并添加两个排除约束。第一个排除约束禁止在周末不回绕的情况下重叠的时间间隔:
第二个排除约束禁止由于其中一个在周末结束而重叠的间隔:
排除约束是有趣的部分,但为了完整起见,表本身看起来像这样:
这是 PostgreSQL 类型的完美用例
RANGE
。下面的所有代码都可以在此处的小提琴上找到。在这里可以找到一篇关于它们的优秀文章(作者 Dimitri Fontaine)——主要要注意的是:
需要注意的关键是范围是有序的——第一个值小于第二个值,所以不用担心在它们完成后开始的无意义的约会(而且我已经看到实际上允许这样做的系统!)。
可以在此处找到一篇关于如何使用它们“将 100 行 SQL 变成 3 行”的有趣帖子(nb多范围类型)。
简单示例表:
所以,这告诉我们,没有人可以与另一个具有相同(人,资源......)的人
intval
重叠。business_id
去测试:
接着:
没问题!
但!
我们得到(正确):
现在有一个不同的
business_id
,但与之前的时间表重叠:结果(如预期):
无需担心周日、周一或时间间隔会超过日、周、月或年的界限。这些范围类型非常强大,非常值得去了解。有关函数和运算符的列表,请参见此处。
根据 OP 的评论,这里有一些代码可以设置某种班次安排。它可能会用 PL/pgSQL 进行一些处理来整理它,对于重复的计划,作为基线,它可能会有所帮助。
你的评论说(大概是作为一个例子)
"Mondays 9AM to 5PM, Tuesdays 10AM to 6PM, ..
,所以我已经迎合了那个例子 - 你显然可以为更复杂的场景添加你自己的代码。你也可以使用上面概述的范围数据类型。结果(为简洁起见被剪掉):
因此,您可以在这里看到(如果您检查小提琴)周一的 09:00 到 17:00 是轮班时间,然后是周二的 10:00 到 18:00 是轮班时间。