Большая часть вашего ответа просто использует lead()
:
select driverid, status, statusdt,
lead(statusdt) over (partition by driverid order by statusdt) as enddte
from t;
Это не дает перерывов на день. Но вы можете добавить их. Я думаю, что самый простой способ - это добавить даты (используя рекурсивный CTE) и вычислить статус в это время. Итак:
Я бы сделал следующее:
- использовать рекурсивный CTE для вычисления дат
- "заполнить" статусы и объединение в исходную таблицу
- используйте
lead()
, чтобы получить дату окончания
Это выглядит так:
with day_boundaries as (
select driverid, dateadd(day, 1, convert(min(statusdt) as date) as statusdt, max(statusdt) as finaldt
from t
group by driverid
having datediff(da, min(statusdt), max(statusdt)) > 0
union all
select driverid, dateadd(day, 1, statusdt), finaldt
from day_boundaries
where statusdt < finaldt
),
unioned as (
select driverid, status, statusdt
from t
union all
select db.driverid, s.status, db.statusdt
from day_boundaries db cross apply
(select top (1) status
from t
where t.statusdt < db.statusdt
order by t.statusdt desc
) s
)
select driverid, status, statusdt,
lead(statusdt) over (partition by driverid order by statusdt) as enddte
from unioned;
Обратите внимание, что это не вычитает ни одной секунды из даты окончания. Дата окончания соответствует предыдущей дате начала. Время непрерывно. Нет смысла иметь пробелы для записей, которые должны плотно прилегать друг к другу.