возможный способ - не самый красивый и, вероятно, не самый лучший - и не уверен, что он будет работать для всех периодов, у вас может быть
код, адаптированный с https://dba.stackexchange.com/questions/174035/split-duration-hourly-depending-on-start-and-end-time
declare @workdate datetime = '2020-03-06'
;
-- may need more rows here depending on how long the events can be
WITH E1(N) AS (
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
),
numbers (n) AS ( SELECT top 24 row_number() over (order by a.n) - 1 FROM E1 a, E1 b)
, inpdata as
(
select convert(datetime, starttime) as Start_timestamp
, convert(datetime, Endtime) as End_timestamp
from (values ('2020-03-06 15:30:40.000', '2020-03-06 17:09:01.000')
,('2020-03-06 22:47:52.000', '2020-03-06 23:48:52.000')
,('2020-03-06 23:49:52.000', '2020-03-07 00:47:52.000')
,('2020-03-09 17:05:26.000', '2020-03-09 18:05:26.000')
,('2020-03-09 18:05:32.000', '2020-03-09 19:05:26.000')
) t (Starttime, Endtime)
)
, workday as
(
SELECT
convert(varchar(13), start_final, 121) as period
, convert(date, start_final) as perioddt
, sum(DATEDIFF(second, start_final, end_final)) Duration
FROM
(
SELECT Start_timestamp
, End_Timestamp
, CASE WHEN t.Start_timestamp > n.start_from_numbers THEN t.Start_timestamp ELSE n.start_from_numbers END start_final
, CASE WHEN t.End_timestamp > n.end_from_numbers THEN n.end_from_numbers ELSE t.End_timestamp END end_final
FROM inpdata t
CROSS APPLY
(
SELECT dateadd(hour, n.n + datediff(hour, 0, t.Start_timestamp), 0) start_from_numbers
, dateadd(hour, 1 + n.n + datediff(hour, 0, t.Start_timestamp), 0) end_from_numbers
FROM numbers n WHERE DATEDIFF(HOUR, t.Start_timestamp, t.End_Timestamp) >= n.n
) n
) t2
group by convert(varchar(13), start_final, 121)
,convert(date, start_final)
)
select workdate
, coalesce(work.duration, 0) as duration
from numbers
cross apply (select convert(varchar(13), dateadd(hour, numbers.n, @workdate), 121) as workdate) dt
outer apply (select *
from workday wd
where wd.period = dt.workdate
) work