Этот тип проблемы известен как ' Пробелы и острова '. Вы определяете последовательные наборы данных (острова) или диапазон значений между двумя островами (разрывы). Есть много разных способов достижения результатов, которые также хорошо работают с большими наборами данных. Вы можете сослаться на следующие хорошо написанные статьи для этого.
https://www.itprotoday.com/sql-server/solving-gaps-and-islands-enhanced-window-functions
https://www.red -gate.com / простой разговор / SQL / T-SQL-программирование /-SQL-из-зазорах-и-острова-в-последовательности /
https://www.sqlshack.com/data-boundaries-finding-gaps-islands-and-more/
Вот попытка вашего вопроса.
CREATE TABLE #test
(
dt DATETIME
,Status INT
,PersonID INT
)
INSERT INTO #Test (dt, Status, PersonID) VALUES
('2018/01/01', 2, 2015),
('2018/01/02', 2, 2015),
('2018/01/05', 2, 2015),
('2018/01/06', 2, 2015),
('2018/01/07', 2, 2015),
('2018/01/11', 2, 2015),
('2018/01/01', 2, 1018),
('2018/01/03', 2, 1018),
('2018/01/05', 2, 1018),
('2018/01/06', 2, 1018),
('2018/01/08', 2, 1018),
('2018/01/09', 2, 1018),
('2018/01/03', 2, 1625),
('2018/01/04', 2, 1625),
('2018/01/05', 2, 1625),
('2018/01/06', 2, 1625),
('2018/01/17', 2, 1625),
('2018/01/29', 2, 1625)
;with cte_dt_from
AS
(
SELECT PersonID, MIN(Dt) dt_from_start
FROM #Test
GROUP BY PersonID
),
cte_offset_num
AS
(
SELECT T1.PersonID, T1.dt, DATEDIFF(DAY, T2.dt_from_start, T1.dt) dt_offset
FROM #test T1
INNER JOIN cte_dt_from T2 ON T2.PersonID = T1.PersonID
),
cte_starting_point
AS
(
SELECT A.PersonID, A.dt_offset, ROW_NUMBER() OVER(PARTITION BY A.PersonID ORDER BY A.dt_offset) AS rownum
FROM cte_offset_num AS A
WHERE NOT EXISTS (
SELECT *
FROM cte_offset_num AS B
WHERE B.PersonID = A.PersonID AND B.dt_offset = A.dt_offset - 1)
)
,
cte_ending_point
AS
(
SELECT A.PersonID, A.dt_offset, ROW_NUMBER() OVER(PARTITION BY A.PersonID ORDER BY A.dt_offset) AS rownum
FROM cte_offset_num AS A
WHERE NOT EXISTS (
SELECT *
FROM cte_offset_num AS B
WHERE B.PersonID = A.PersonID AND B.dt_offset = A.dt_offset + 1)
)
SELECT (E.dt_offset - S.dt_offset) + 1 AS [count], S.PersonID
FROM cte_starting_point AS S
JOIN cte_ending_point AS E ON E.PersonID = S.PersonID AND E.rownum = S.rownum
ORDER BY S.PersonID;
DROP TABLE #Test;