使用 PostgreSQL 范围类型查找冲突的计划

Posted

技术标签:

【中文标题】使用 PostgreSQL 范围类型查找冲突的计划【英文标题】:Finding Conflicting Schedules with PostgreSQL Range Types 【发布时间】:2022-01-23 19:40:44 【问题描述】:

问题

我们有一张表来处理为用户安排假期和一些业务规则,即某些人群不能同时外出。调度表的相关部分看起来像

user_id (text) out_date_range (daterange)
1 ["2021-12-27", "2021-12-30")
2 ["2021-12-24", "2021-12-30")
3 ["2022-01-24", "2022-01-27")
1 ["2022-01-18", "2022-01-23")
2 ["2022-01-25", "2022-01-30")

我们的目标是找出给定用户x 是否可以使用date_range = [A,B) 创建一个新的假期计划,给定一个不能与x 同时外出的用户列表。

示例

例如,假设用户 1 想要使用 date_range ["2022-01-26", "2022-01-29") 创建一个新的假期计划,并且我们知道用户 1、2 和 3 不能同时外出。我们的查询应表明无法安排此活动,因为用户 2 和 3 都已在 2022 年 1 月 26 日外出(请参阅附加说明中的第 2 点)。

附加说明

    群组中不能同时出去的用户数是动态的,会作为user_id的列​​表传入 查询只需要指明是否可以调度(真/假);如果我们可以另外指出哪个日期范围会导致冲突,那会很好,但这不是必需的。 我们使用的是 PostgreSQL 12.6 版(所以没有multirange functionality)

(天真)尝试的解决方案

    为“不能一起出去”组中的所有用户创建一个交集聚合器和交集计划。如果每个用户只有一个时间表,这会起作用(我认为),但由于用户有多个不会重叠的时间表,所以交叉点总是空的。 尝试交叉加入(组中的每个用户一个)以生成可能发生冲突的可能日期范围,然后在这些范围内相交。我在这里感到困惑,因为交叉连接的数量是动态的,即使我们最终得到正确的元组,也不确定交叉连接的实际工作方式。

【问题讨论】:

【参考方案1】:

使用 PostgreSQL v14,您可以运行以下查询来确定新条目是否会与以前的条目冲突:

SELECT range_intersect_agg(mr)
FROM (SELECT range_agg(out_date_range) AS mr
      FROM mytable
      WHERE user_id <> '1' GROUP BY user_id) AS q
WHERE mr && '["2022-01-26", "2022-01-29")'::daterange;

这需要新的多范围数据类型。

首先,我们为除用户 1 之外的每个用户构建一个多范围的关闭时间,然后我们通过相交来查看所有这些多范围中是否有任何日期。如果结果不为空,则存在冲突。

这不能通过数据库约束来完成,因此请使用锁定 (SELECT ... FOR NO KEY UPDATE) 或 SERIALIZABLE 事务来防止异常。

【讨论】:

感谢您的快速回复!不幸的是,我认为这还不够,因为不仅仅是在那段时间有假期的用户数量,还有假期发生的时间。例如,仍然假设用户 1 试图安排从 2022-01-26 到 2022-01-29 的假期,如果用户 2 从 2022-01-26 到 2022-01-27 外出并且用户 3 从 2022 年外出-01-28 到 2022-01-30,那么用户 2 和用户 3 将与一个用户 1 尝试安排的假期重叠,但从来没有时间三个人同时外出(因为用户 2 和3 个假期不重叠)。 是的。我已经用 PostgreSQL v14 的解决方案更新了我的答案。也许你可以升级。 我真的希望避免这种情况,但如果我们最终求助于它,我将感谢您的帮助。另外,感谢最后一句,我对可能的并发问题考虑得不够多。

以上是关于使用 PostgreSQL 范围类型查找冲突的计划的主要内容,如果未能解决你的问题,请参考以下文章

sql执行计划

PostgreSQL:查找有关用户定义类型的信息

项目管理/PMP/PMBOK第六版/第七版/新考纲PMP错题解析 | 识别相关方应急计划管理者的责任关键路径法WBS三点估算定义范围冲突管理工料合同假设日志

项目管理/PMP/PMBOK第六版/第七版/新考纲PMP错题解析 | 识别相关方应急计划管理者的责任关键路径法WBS三点估算定义范围冲突管理工料合同假设日志

postgresql数据库——数据类型总结

获取错误“选择表数据时,参数类型错误,超出可接受的范围或彼此冲突”