根据时间间隔划分时间段

时间:2018-11-06 10:32:13

标签: sql oracle gaps-and-islands

我有一个表,其中包含代表'person-career'的多个时间段,在同一表中,我所有与同一个人(即holidays, illnesses ...相关的中断)。

该表中使用的订单是(按codeMission的顺序,然后是year,然后是工作类型,然后是Holidays期)

 Date begin Date end   Type    codeMission  year  name
 ---------- --------------------------------------------
 2001-01-01 2001-12-31 Working     Tx100     2001  James
 2001-05-01 2001-05-12 holidays    Tx100     2001  James

我想按假期划分工作时间

 Date begin Date end   Type    codeMission  year  name
 ---------- -----------------------------------------
 2001-01-01 2001-04-30 Working    Tx100     2001  James
 2001-05-01 2001-05-12 holiday    Tx100     2001  James
 2001-05-13 2001-12-31 Working    Tx100     2001  James

有一般的方法吗?如您所知,假期/疾病时间有时可以在某些时间之前和之后。

问题1:如何获得所有列的这种格式?我想在这里提一个具体的内容, 问题2:何时将假期定义为两年。例如:

Date begin Date end   Type    codeMission  year  name
 ---------- --------------------------------------------
 2001-01-01 2001-12-31 Working     Tx100     2001  James
 2001-10-11 2002-04-30 holidays    Tx100     2001  James
 2002-01-01 2001-12-31 Working     Tx100     2002  James

在这里我们将收到多个问题!分期不正确! 你怎么了?

1 个答案:

答案 0 :(得分:4)

这很复杂。这个想法是“取消透视”日期并跟踪type在每天进出的情况。然后,您可以使用累积总和来跟踪实际类型。

所以:

with t as (
      select date '2001-01-01' as sdate, date '2001-12-31' as edate, 'Working' as type from dual union all
      select date '2001-05-01' as sdate, date '2001-05-12' as edate, 'holidays' from dual
     ),
     d as (
      select sdate as dte, type, 1 as flag from t union all
      select edate + 1, type, -1 as flag from t
     )
select d.dte, lead(dte) over (order by dte) - 1 as enddte,
       (case when flag = -1 then lag(type) over (partition by grp order by dte) else type end) as type
from (select d.*, sum(flag) over (order by dte) as grp
      from d
     ) d
order by dte;

Here是db <>小提琴。

编辑:

Here是改进的版本:

with t as (
      select date '2001-01-01' as sdate, date '2001-12-31' as edate, 'Working' as type from dual union all
      select date '2001-05-01' as sdate, date '2001-05-12' as edate, 'holidays' from dual union all
      select date '2001-07-01' as sdate, date '2001-08-12' as edate, 'holidays' from dual
     ),
     d as (
      select sdate as dte from t union all
      select edate + 1 from t
     )
select d.dte, d.enddte,
       (select max(t2.type) keep (dense_rank first order by t2.sdate desc)
        from t t2
        where t2.sdate <= d.dte and t2.edate >= d.enddte
       ) as type 
from (select d.*, lead(dte) over (order by dte) - 1 as enddte
      from d
     ) d
where dte <= enddte
order by d.dte

此方法仅获取各个期间(通过分解原始期间)。然后,对于每个时间段,它会找到在该时间段内有效的type。那是涵盖整个时期的最新记录。

请注意,由于日期是“相邻的”,因此不会部分覆盖各个期间。