Слегка другой такт до
Я создал таблицу Temp - полное решение см. В [SQLFiddle] 1
Я создал Grpи столбец StartDate_Plus, как показано ниже
;WITH Numbers (Number) AS
( SELECT ROW_NUMBER() OVER(ORDER BY N1.N) - 1
FROM (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) N1(N)
CROSS JOIN (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) N2 (N)
CROSS JOIN (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) N3 (N)
CROSS JOIN (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) N4 (N)
)
SELECT
D.UserId
,D.StartDate
,D.EndDate
,StartDate_Plus = DATEADD(HOUR, N.Number, D.StartDate) --Only for Ordering of ResultSet below
,N.Number
,Grp = MAX(N.Number)OVER(PARTITION BY UserId, StartDate)
FROM
dbo.T1 D
INNER JOIN Numbers N ON N.Number <= DATEDIFF(HOUR, D.StartDate, D.EndDate)
Вывод примерно так
UserId StartDate EndDate StartDate_Plus Number Grp
1033 2018-06-24 00:11:51.0000000 2018-06-24 01:03:38.0000000 2018-06-24 00:11:51.0000000 0 1
1033 2018-06-24 00:11:51.0000000 2018-06-24 01:03:38.0000000 2018-06-24 01:11:51.0000000 1 1
1033 2018-06-24 02:12:38.0000000 2018-06-24 02:15:51.0000000 2018-06-24 02:12:38.0000000 0 0
1033 2018-06-24 02:28:08.0000000 2018-06-24 02:36:31.0000000 2018-06-24 02:28:08.0000000 0 0
1033 2018-06-24 03:07:13.0000000 2018-06-24 06:02:05.0000000 2018-06-24 03:07:13.0000000 0 3
1033 2018-06-24 03:07:13.0000000 2018-06-24 06:02:05.0000000 2018-06-24 04:07:13.0000000 1 3
1033 2018-06-24 03:07:13.0000000 2018-06-24 06:02:05.0000000 2018-06-24 05:07:13.0000000 2 3
1033 2018-06-24 03:07:13.0000000 2018-06-24 06:02:05.0000000 2018-06-24 06:07:13.0000000 3 3
Столбец StartDate_plus просто добавляет [Количество] часов к StartDate
и Grp
просто для предоставлениясгруппировать несколько строк для одного и того же события
Добавив этот дополнительный CTE, вы можете затем показать Dummy StartDate_
и EndDate_
для каждого часа, что событие больше, чем один час, например
;WITH Numbers (Number) AS
( SELECT ROW_NUMBER() OVER(ORDER BY N1.N) - 1
FROM (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) N1(N)
CROSS JOIN (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) N2 (N)
CROSS JOIN (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) N3 (N)
CROSS JOIN (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) N4 (N)
),cteStartDate_Plus
AS(
SELECT
D.UserId
,D.StartDate
,D.EndDate
,StartDate_Plus = DATEADD(HOUR, N.Number, D.StartDate) --Only for Ordering of ResultSet below
,N.Number
,Grp = MAX(N.Number)OVER(PARTITION BY UserId, StartDate)
FROM
dbo.T1 D
INNER JOIN Numbers N ON N.Number <= DATEDIFF(HOUR, D.StartDate, D.EndDate)
)
SELECT TOP 100 PERCENT
UserId, StartDate, EndDate, Grp
,CS.StartDate_Plus
,CS.Number
,[StartDate_] = CASE --apply some rounding to the StartDate if required
WHEN Number = 0 THEN CS.StartDate
ELSE DATEADD(hour, DATEDIFF(HOUR, 0, CS.StartDate_Plus), 0)
END
,[EndDate_] = CASE --apply some rounding to the EndDate if required
WHEN CS.Number = CS.Grp THEN CS.EndDate
WHEN CS.StartDate_Plus > CS.EndDate THEN CS.EndDate
WHEN CS.Number <> CS.Grp AND CS.StartDate_Plus <= CS.EndDate
THEN DATEADD(HOUR, DATEDIFF(HOUR, 0, DATEADD(MINUTE, 30 + DATEPART(MINUTE, DATEADD(MINUTE, 30, CS.StartDate_Plus)),CS.StartDate_Plus)), 0)
END
,[Hour] = CONVERT(TIME(0), DATEADD(HOUR, DATEPART(HOUR, CS.StartDate_Plus), 0))
FROM
cteStartDate_Plus CS
ORDER BY
UserId, CS.StartDate_Plus
Затем инкапсулирует вышеуказанный запрос в другой CTE, который называется CteDummyDates. Следующий запрос просто предоставит вам нужные результаты
SELECT
UserId
,[Date] = CONVERT(DATE, DD.StartDate_Plus)
,DD.[Hour]
,[Seconds_in] = DATEDIFF(SECOND, DD.StartDate_, DD.EndDate_)
FROM
cteDummyDates DD
ORDER BY
DD.UserId, DD.StartDate_
Вывод
UserId Date Hour Seconds_in
1033 2018-06-24 00:00:00 2889
1033 2018-06-24 01:00:00 218
1033 2018-06-24 02:00:00 193
1033 2018-06-24 02:00:00 503
1033 2018-06-24 03:00:00 3167
1033 2018-06-24 04:00:00 3600
1033 2018-06-24 05:00:00 3600
1033 2018-06-24 06:00:00 125
1033 2018-06-24 07:00:00 1
1033 2018-06-24 08:00:00 2441
1033 2018-06-24 09:00:00 3600