Oracle SQL组问题

Oracle SQL组问题,sql,oracle,gaps-and-islands,Sql,Oracle,Gaps And Islands,我试图对一个员工在一个团队中时存在多条记录的员工表进行汇总。我曾尝试按分组、最小/最大超过分区和领先/滞后团队名称,但每个结果都以一个代理结束,该代理已从一个团队移动,然后在稍后的日期作为一个事件返回到原始团队组,即使我按日期排序 示例数据库: Employee Name | Employee ID | Team Leader | Location | Start Date | End Date John Smith | 123123 | Team A | Site

我试图对一个员工在一个团队中时存在多条记录的员工表进行汇总。我曾尝试按分组、最小/最大超过分区和领先/滞后团队名称,但每个结果都以一个代理结束,该代理已从一个团队移动,然后在稍后的日期作为一个事件返回到原始团队组,即使我按日期排序

示例数据库:

Employee Name | Employee ID | Team Leader | Location | Start Date | End Date

John Smith    | 123123      | Team A      | Site A   | 01/JAN/19  | 02/JAN/19

John Smith    | 123123      | Team A      | Site A   | 02/JAN/19  | 03/JAN/19

John Smith    | 123123      | Team B      | Site A   | 03/JAN/19  | 04/JAN/19

John Smith    | 123123      | Team A      | Site A   | 04/JAN/19  | 05/JAN/19

John Smith    | 123123      | Team B      | Site A   | 05/JAN/19  | 06/JAN/19
运行示例查询时:

SELECT
Employee Name
,Employee ID
,Team Leader
,Location
,MIN(Start Date) OVER(PARTITION BY Team Leader ORDER BY Employee ID, Start Date) AS Starting Date
,MAX(End Date) OVER(PARTITION BY Team Leader ORDER BY Employee ID, End Date) AS End Date
FROM TABLE 1
结果如下:

Employee Name | Employee ID | Team Leader | Location | Start Date | End Date

John Smith    | 123123      | Team A      | Site A   | 01/JAN/19  | 05/JAN/19

John Smith    | 123123      | Team B      | Site A   | 03/JAN/19  | 06/JAN/19
任何人都可以帮助实现预期的结果:

Employee Name | Employee ID | Team Leader | Location | Start Date | End Date

John Smith    | 123123      | Team A      | Site A   | 01/JAN/19  | 03/JAN/19

John Smith    | 123123      | Team B      | Site A   | 03/JAN/19  | 04/JAN/19

John Smith    | 123123      | Team A      | Site A   | 04/JAN/19  | 05/JAN/19

John Smith    | 123123      | Team B      | Site A   | 05/JAN/19  | 06/JAN/19

这看起来像是一种间隙和孤岛的形式,其中记录通过日期范围链接

下面是一种使用左连接查找孤岛起始位置的方法,然后是用于标识组和聚合的累积和:

select employeename, employeeid, teamleader, location,
       min(startdate), max(enddate)
from (select t1.*,
             sum(case when tprev.employeeid is null  -- new group
                      then 1 else 0
                 end) over (partition by employeeid, teamleader, location
                            order by startdate
                           ) as grouping
      from table1 t1 left join
           table1 tprev
           on t1.startdate = tprev.enddate and
              t1.employeeid = tprev.employeeid and
              t1.teamleader = tprev.teamleader and
              t1.location = tprev.location
     ) t
group by employeeid, teamleader, location, grouping
order by employeeid, min(startdate);
这里有一个选择:

测试CTE表示您的数据稍微简化了一点 有用的代码是从第8行开始的
如果您有12c或更高版本,行模式匹配是一个很好的替代解决方案。与缺口和孤岛解决方案不同,我也处理重叠。WITH子句包含测试数据,解决方案随后开始

with test (ename, team, start_date, end_date) as
 (select 'John', 'A', date '2019-01-01', date '2019-01-02' from dual union all
  select 'John', 'A', date '2019-01-02', date '2019-01-03' from dual union all
  select 'John', 'B', date '2019-01-03', date '2019-01-04' from dual union all
  select 'John', 'A', date '2019-01-04', date '2019-01-05' from dual union all
  select 'John', 'B', date '2019-01-05', date '2019-01-06' from dual
 )
select * from test
match_recognize(
  partition by ename, team order by start_date
  measures first(start_date) start_date, last(end_date) end_date
  pattern(a b*)
  define b as start_date <= a.end_date
)
order by ename, start_date;

ENAM T START_DATE       END_DATE        
---- - ---------------- ----------------
John A 2019-01-01 00:00 2019-01-03 00:00
John B 2019-01-03 00:00 2019-01-04 00:00
John A 2019-01-04 00:00 2019-01-05 00:00
John B 2019-01-05 00:00 2019-01-06 00:00

寻找缺口和岛屿。这是一个重复的问题,尽管我很难找到最适合这里的答案。解决方案类似于。@Poundstibbons我从您提供的链接中测试了一个类似的逻辑,它似乎可以工作。我将在向查询中添加更多员工时进行验证。谢谢非常感谢,这似乎解决了我的问题,并正确地将代理分组。
with test (ename, team, start_date, end_date) as
 (select 'John', 'A', date '2019-01-01', date '2019-01-02' from dual union all
  select 'John', 'A', date '2019-01-02', date '2019-01-03' from dual union all
  select 'John', 'B', date '2019-01-03', date '2019-01-04' from dual union all
  select 'John', 'A', date '2019-01-04', date '2019-01-05' from dual union all
  select 'John', 'B', date '2019-01-05', date '2019-01-06' from dual
 )
select * from test
match_recognize(
  partition by ename, team order by start_date
  measures first(start_date) start_date, last(end_date) end_date
  pattern(a b*)
  define b as start_date <= a.end_date
)
order by ename, start_date;

ENAM T START_DATE       END_DATE        
---- - ---------------- ----------------
John A 2019-01-01 00:00 2019-01-03 00:00
John B 2019-01-03 00:00 2019-01-04 00:00
John A 2019-01-04 00:00 2019-01-05 00:00
John B 2019-01-05 00:00 2019-01-06 00:00