使用SQL确定两个日期范围是否重叠

使用SQL确定两个日期范围是否重叠,sql,postgresql,datetime,Sql,Postgresql,Datetime,我们内部构建的软件中存在这样一种情况:我们接受start\u time TIMESTAMP和end\u time TIMESTAMP NULL,以使策略生效。这里重要的一点是结束日期也可以为空,这意味着除非明确结束,否则策略可以无限期地生效。我见过一些关于stackoverflow的解决方案,但要么它们不是基于SQL的,要么给定end\u time not NULL。我们希望确保添加新策略时不会与现有策略重叠 下面给出了策略表的示例模式 CREATE TABLE public.policies

我们内部构建的软件中存在这样一种情况:我们接受
start\u time TIMESTAMP
end\u time TIMESTAMP NULL
,以使策略生效。这里重要的一点是结束日期也可以为空,这意味着除非明确结束,否则策略可以无限期地生效。我见过一些关于stackoverflow的解决方案,但要么它们不是基于SQL的,要么给定
end\u time not NULL
。我们希望确保添加新策略时不会与现有策略重叠

下面给出了策略表的示例模式

CREATE TABLE public.policies
(
    id uuid,
    start_time timestamp without time zone NOT NULL,
    end_time timestamp without time zone,
    PRIMARY KEY (id)
);
示例数据源

INSERT INTO policies (id, start_time, end_time) VALUES
('5c056e24-9633-4bb9-b231-fbcab2d4e943', '2020-09-01 00:00:00', '2020-09-05 23:59:59'),
('4e38fd23-6f41-4022-addd-6e3feaa838e0', '2020-09-06 00:00:00', '2020-09-06 23:59:59'),
('e41fe1e5-e433-40a2-9d07-d046f8ca4bfc', '2020-09-07 00:00:00', NULL);

非常感谢您的帮助。

我们假设您有新策略的参数:start和:end。然后,以下逻辑返回与该时间段重叠的所有现有行:

select p.*
from policies p
where p.start_time < :end and (p.end_time > :start or p.end_time is null);
选择p*
来自政策p
其中p.start\u time<:end和(p.end\u time>:start或p.end\u time为空);
两个时间段重叠是指一个时间段在第二个时间段结束之前开始,另一个时间段在第二个时间段结束之后结束。

这就是方便的地方:

select *
from policies
where tsrange(start_time, end_time, '[]') && tsrange(check_start, check_end, '[]');
check\u start
check\u end
将是您要检查的参数。上述示例中的范围是“闭合”范围,即,包括两条边。例如,如果上限是独占的,请使用
'[)'

空值等于“no end”,因此这将自动处理


使用tsrange,您还可以创建一个防止插入重叠范围的模式。

以下是我用来考虑where子句中可能为空值的模式

选择*
从表\u名称
其中开始时间<:结束和(结束时间为空或结束时间>:开始);

非常感谢您的快速回复。如果任何现有的策略结束时间为空,我们如何抓住它呢?@AppDevD…您的问题中确实有这个问题,不是吗。我已修复了答案。@a_horse_,没有名字感谢您指出这一点。我现在正在编辑此答案。此答案看起来很有希望,但我发现的唯一例外是它没有通过when check_end为null我已经添加了要运行的示例架构和测试数据。我运行的未通过的测试是
select*from policies where(start_time,end_time)重叠('2020-09-01 00:00:00:00',null);
@AppDevD:如果
重叠()
处理不正确,请使用tsrangeWorked。你是个英雄。谢谢。