所有工作人员的日期范围重叠

Overlapping date ranges for all workers

我想弄清楚如何计算所有 名员工一起 工作的日期范围(岛屿)。换句话说,如果其中一名工人不在某个日期,则该日期应从结果中排除。以下示例数据:

insert into WORK_DAYS(WORKER_ID, DATE_FROM, DATE_TO) VALUES(1, '2019-10-01', '2020-04-30');
insert into WORK_DAYS(WORKER_ID, DATE_FROM, DATE_TO) VALUES(1, '2020-05-01', '2020-07-19');
insert into WORK_DAYS(WORKER_ID, DATE_FROM, DATE_TO) VALUES(1, '2020-10-01', '9999-01-01');
insert into WORK_DAYS(WORKER_ID, DATE_FROM, DATE_TO) VALUES(2, '2019-10-01', '2020-04-30');
insert into WORK_DAYS(WORKER_ID, DATE_FROM, DATE_TO) VALUES(2, '2020-05-01', '2020-07-31');
insert into WORK_DAYS(WORKER_ID, DATE_FROM, DATE_TO) VALUES(2, '2020-11-01', '9999-01-01');
insert into WORK_DAYS(WORKER_ID, DATE_FROM, DATE_TO) VALUES(3, '2018-03-12', '2018-08-20');
insert into WORK_DAYS(WORKER_ID, DATE_FROM, DATE_TO) VALUES(3, '2019-10-01', '2020-04-15');
insert into WORK_DAYS(WORKER_ID, DATE_FROM, DATE_TO) VALUES(3, '2020-07-01', '2020-07-31');
insert into WORK_DAYS(WORKER_ID, DATE_FROM, DATE_TO) VALUES(3, '2020-11-01', '9999-01-01');

我使用 Firebird 数据库,但您可以在任何数据库中显示结果,例如 SQL 服务器(但请不要交叉应用仅在 SQL 标准中定义的内容)。这是已经从 gaps/islands 问题中检索到的简化数据。实际上 worker_id 在我的样本中是整个团队。

我知道如何找到重叠的日期范围,但我不知道如何找到同时应用于所有工作人员的重叠日期范围。

假设工人没有重叠,您可以为此使用计数技巧。计算每个日期工作的工人数。那么所有工人的日期就是你想要的日期。

您实际上并不需要每次约会。假设 date_to 包括 作为一个工作日,您可以对数据进行逆透视并使用累计总和。

Postgres 中表达的逻辑如下(您的问题确实指定了任何数据库中的解决方案都是可以接受的,我发现 Postges 最接近标准 SQL):

with wd as (
      select worker_id, date_from as dte, 1 as inc
      from work_days wd
      union all
      select worker_id, date_to + interval '1 day', -1 as inc
      from work_days wd
     ),
     wd_cnt as (
      select wd.dte, sum(sum(inc)) over (order by dte) as num_on_date,
             lead(wd.dte) over (order by wd.dte) as next_dte
      from wd
      group by wd.dte
     )
select dte, next_dte - interval '1 day'
from wd_cnt
where num_on_date = (select count(distinct worker_id) from work_days);

这都是标准的 SQL,但是 date/time 功能因数据库而异。请注意,这会在 date_to 上增加一天,因此不要为此值使用绝对最大日期。

Here 是一个 db<>fiddle.