хорошо, поэтому я сгенерировал CTE, содержащий даты для всей рассматриваемой даты.
Для каждой из этих дат я сгенерировал FLAG = 1, где, как мне кажется, я обнаружил наложение.
Затем я использовал row_number () в качестве стандартного решения проблемы «островов», и я выводил время начала и окончания «островков» флага = 1
Надеюсь, это поможет, я получу ваши результаты за 13570, но, поскольку я понимаю, «перекрывают» все 13579 совпадений. Возможно, эта часть нуждается в дополнительном объяснении, адаптации. Если вы сможете понять, как генерировать FLAG в соответствии с вашими правилами, часть рейтинга все равно будет применяться
CREATE TABLE #EventsTBL
(
PID INT,
EID INT,
StartDate DATETIME,
EndDate DATETIME
);
INSERT INTO #EventsTBL
VALUES
(13579, '1', '01 Jan 2018', '31 Mar 2019'),
(13579, '2', '01 Feb 2018', '31 May 2018'),
(13579, '2', '01 Jul 2018', '31 Jan 2019'),
(13579, '7', '01 Mar 2018', '31 Mar 2019'),
(13579, '5', '01 Feb 2018', '30 Apr 2018'),
(13579, '5', '01 Oct 2018', '31 Mar 2019'),
(13579, '8', '01 Jan 2018', '30 Apr 2018'),
(13579, '8', '01 Jun 2018', '31 Dec 2018'),
(13579, '13', '01 Jan 2018', '31 Mar 2019'),
(13579, '6', '01 Apr 2018', '31 May 2018'),
(13579, '6', '01 Sep 2018', '30 Nov 2018'),
(13579, '4', '01 Feb 2018', '31 Jan 2019'),
(13579, '19', '01 Mar 2018', '31 Jul 2018'),
(13579, '19', '01 Oct 2018', '28 Feb 2019'),
--
(13570, '16', '01 Feb 2018', '30 Jun 2018'),
(13570, '16', '01 Aug 2018', '31 Aug 2018'),
(13570, '16', '01 Oct 2018', '28 Feb 2019'),
(13570, '23', '01 Mar 2018', '30 Jun 2018'),
(13570, '23', '01 Nov 2018', '31 Jan 2019');
SELECT count(enddate) FROM (SELECT CAST('19660423' as date) dt) A LEFT JOIN #EventsTBL B ON A.dt = b.StartDate;
WITH MIN_MAX AS (SELECT MIN(StartDate) S , MAX(EndDate) E FROM #EventsTBL ),
ALL_DATES AS (SELECT S DT FROM MIN_MAX
UNION ALL
SELECT DATEADD(day,1,DT) FROM ALL_DATES WHERE DT < (SELECT E FROM MIN_MAX)
),
BuildFlags AS (SELECT P.pid,
DT,
COUNT(e.PID ) CNT,
CASE WHEN COUNT(e.pid) > 1 THEN 1 ELSE 0 END FLAG,
row_number() OVER(partition by p.pid order by DT) RN
FROM ALL_DATES A CROSS JOIN (SELECT DISTINCT E2.pid FROM #EventsTBL E2) P
LEFT JOIN
#EventsTBL E ON P.PID = E.pid AND
A.DT BETWEEN E.StartDate AND E.EndDate GROUP BY P.pid,DT),
AddRanks AS (SELECT *,rn - row_number()over(partition by pid,flag order by dt) groupRank FROM BuildFlags)
select pid,min(dt) as start, max(dt) as ending from AddRanks
where flag = 1
group by pid,grouprank
order by pid,min(dt)
option(maxrecursion 0)
РЕДАКТИРОВАТЬ - Я думаю, что я видел, что вы имеете в виду, вы хотите объединить pid и eid в уникальный pid и eid с датой, которая там есть. Затем вы определяете перекрытие, так как все pid и eid активны одновременно. Вот и я придумал эту модификацию
;WITH MIN_MAX AS (SELECT MIN(StartDate) S , MAX(EndDate) E FROM #EventsTBL ),
ALL_DATES AS (SELECT S DT FROM MIN_MAX
UNION ALL
SELECT DATEADD(day,1,DT) FROM ALL_DATES WHERE DT < (SELECT E FROM MIN_MAX)
),
GROUPED AS (SELECT Q.pid,Q.eid,q.dt,case when max(tx.pid) is null then 0 else 1 end YES from (Select * FROM All_Dates cross join (select distinct pid,eid from #EventsTBL) AQ) Q
LEFT JOIN #EventsTBL TX ON TX.PID = Q.pid and tx.EID = Q.eid and
Q.DT BETWEEN TX.StartDate AND TX.EndDate GROUP BY q.pid,q.eid,q.dt
),
BuildFlags AS (SELECT g.pid,g.dt, row_number() OVER(partition by g.pid order by g.DT) RN,
CASE WHEN WQ.tot = (SELECT count(distinct g2.eid) FROM grouped g2 WHERE g2.PID = G.pid and g2.dt=g.dt and g2.yes=1) then 1 else 0 end FLAG
FROM GROUPED G cross apply (select count(distinct E9.eid) tot FROM #EventsTBL E9 WHERE E9.PID = G.pid) WQ)
,AddRanks AS (SELECT *,rn - row_number()over(partition by pid,flag order by dt) groupRank FROM BuildFlags)
select pid,min(dt) as start, max(dt) as ending from AddRanks
where flag = 1
group by pid,grouprank
order by pid,min(dt)
option(maxrecursion 0);