Reputation: 6784
I have the following table
EmpId Date StartOn EndOn
0001 2-Feb-17 590 599
0002 2-Feb-17 600 609
0003 2-Feb-17 610 619
0004 2-Feb-17 626 635
0002 2-Feb-17 630 639
0004 2-Feb-17 640 649
0005 3-Feb-17 630 639
and I want the output to be like this
EmpId Date StartOn EndOn Overlapping Num
0001 2-Feb-17 590 599 0 1
0002 2-Feb-17 600 609 0 1
0003 2-Feb-17 610 619 0 1
0004 2-Feb-17 626 635 1 1
0002 2-Feb-17 630 639 1 2
0004 2-Feb-17 640 649 0 1
0005 3-Feb-17 630 639 0 1
here a sample of data
create table Data(
EmpId nvarchar(4),
Date date,
StartOn int,
EndOn int
);
insert into Data(EmpId,Date,StartOn,EndOn)
values('0001','02 Feb 2017',590,599),
('0002','02 Feb 2017',600,609),
('0003','02 Feb 2017',610,619),
('0004','02 Feb 2017',626,635),
('0002','02 Feb 2017',630,639),
('0004','02 Feb 2017',640,649),
('0005','03 Feb 2017',630,639)
Requirements : I want to know how many overlapping occurs between
StartOn
andEndOn
on given date and to sort these overlapping by theStartOn
, for exampleEmpId
( 0004 overlaps withEmpId
0002 between range 626 and 639 ( overlap occurs between range 630 and 635), soOverlapping
column will hold the number of overlaps andNum
will hold the number of order byStartOn
This what I tried
;with overlapping as(
select a.EmpId,a.Date,a.StartOn,a.EndOn,count(b.EmpId) as Num
from #Data a
left join #Data b on a.Date = b.Date
and a.StartOn<=b.EndOn and a.EndOn>=b.StartOn and b.EmpId<>a.EmpId
group by a.EmpId,a.Date,a.StartOn,a.EndOn
)
select *,rank() over(partition by Date,Num order by StartOn) as Row
from overlapping
order by Date,StartOn,EmpId
I tried the row_number
and rank
but failed to get any desired result
Upvotes: 0
Views: 35
Reputation: 1269513
I would tend to do this with exists
rather than a self join. Then, on top of exists, a cumulative sum to define the "groups" and then row_number()
:
with d as (
select d.*,
(case when exists (select 1
from #data d2
where d2.StartOn <= d.EndOn and
d2.EndOn >= d.StartOn and
d2.EmpId <> d.EmpId
)
then 1 else 0
end) as IsOverlap
from #data d
)
select d.*, row_number() over (partition by grp order by StartOn) as num
from (select d.*, sum(IsOverlap) over (order by StartOn) as grp
from d
) d;
However, I'm not 100% sure this meets your needs. What should the results be when there are more overlaps? What happens if an EmpId
overlaps with him/her self?
Upvotes: 1
Reputation: 6784
I managed to solve it by adding the iif
inside the partition
;with overlapping as(
select a.EmpId,a.Date,a.StartOn,a.EndOn,count(b.EmpId) as Num
from #Data a
left join #Data b on a.Date = b.Date
and a.StartOn<=b.EndOn and a.EndOn>=b.StartOn and b.EmpId<>a.EmpId
group by a.EmpId,a.Date,a.StartOn,a.EndOn
)
select *,row_number() over(partition by Date,iif(Num=0,StartOn,Num) order by StartOn) as Row
from overlapping
order by Date,StartOn,EmpId
but i am looking for better solution
Upvotes: 0
Reputation: 82474
Here is one way to do it:
;WITH CTE AS
(
SELECT EmpId,
[Date],
StartOn,
EndOn,
ISNULL((
SELECT 1
FROM Data t2
WHERE t2.EmpId <> t1.EmpId
AND t2.[Date] = t1.[Date]
AND t2.StartOn < t1.EndOn
AND t2.EndON > t1.StartOn
), 0) As Overlapping
FROM Data t1
)
SELECT EmpId,
[Date],
StartOn,
EndOn,
Overlapping,
ISNULL(NULLIF(Overlapping, 0) + LAG(Overlapping) OVER (ORDER BY [Date], StartOn, EndOn), 0) As Num
FROM CTE
With the sample data you provided, the result is:
EmpId Date StartOn EndOn Overlapping Num
0001 02.02.2017 590 599 0 0
0002 02.02.2017 600 609 0 0
0003 02.02.2017 610 619 0 0
0004 02.02.2017 626 635 1 1
0002 02.02.2017 630 639 1 2
0004 02.02.2017 640 649 0 0
0005 03.02.2017 630 639 0 0
Upvotes: 0