这是一个线性分割的问题。在您的情况下,您的线性度量是时间。这是我在 SQL Server 中执行此操作的方法。你的旅费可能会改变。我添加了一些额外的输入来演示处理一些极端情况。
declare @MyTable table (
[Date.] date not null,
[ID.] varchar(6) not null,
[Status.] varchar(10) not null
)
insert @MyTable
values
({d '2021-10-01'}, 'Abc123', 'InActive')
, ({d '2021-10-02'}, 'Abc123', 'InActive')
, ({d '2021-10-03'}, 'Abc123', 'Active')
, ({d '2021-10-04'}, 'Abc123', 'Active')
, ({d '2021-10-05'}, 'Abc123', 'Active')
, ({d '2021-10-06'}, 'Abc123', 'InActive')
, ({d '2021-10-07'}, 'Abc123', 'Active')
, ({d '2021-10-08'}, 'Abc123', 'InActive')
, ({d '2021-10-09'}, 'Abc123', 'InActive')
, ({d '2021-10-01'}, 'Def456', 'InActive')
, ({d '2021-10-02'}, 'Def456', 'InActive')
, ({d '2021-10-03'}, 'Def456', 'Active')
, ({d '2021-10-04'}, 'Def456', 'Active')
;
with a as (
select lag([ID.]) over(order by [ID.], [Date.]) as IDPrior
, [ID.]
, lead([ID.]) over(order by [ID.], [Date.]) as IDNext
, lag([Status.]) over (order by [ID.], [Date.]) as StatusPrior
, [Status.]
, lead([Status.]) over (order by [ID.], [Date.]) as StatusNext
, [Date.]
, row_number() over (order by [ID.], [Date.]) as 'RowNum'
from @MyTable
)
, b as (
select *
, CASE
WHEN RowNum = 1
THEN 'BEGIN'
WHEN IDPrior <> [ID.]
THEN 'BEGIN'
WHEN StatusPrior <> [Status.]
THEN 'BEGIN'
ELSE 'Continue'
END as SegmentBegin
, CASE
WHEN [ID.] <> IDNext
THEN 'END'
WHEN [Status.] <> StatusNext
THEN 'END'
WHEN RowNum = max(rownum) over ()
THEN 'END'
ELSE 'Continue'
END as SegmentEnd
from a
)
, c as (
select [ID.]
, [Status.]
, [Date.]
, case when SegmentBegin = 'BEGIN' then [Date.] end as BeginDate
, case when SegmentEnd = 'END' then [Date.] end as EndDate
from b
where SegmentBegin = 'BEGIN'
or SegmentEnd = 'END'
)
, d as (
select [ID.]
, [Status.]
, [Date.]
, BeginDate
, case when EndDate is null and lead([ID.]) over (order by [ID.], [Date.]) = [ID.] then lead(EndDate) over (order by [ID.], [Date.]) else EndDate end as EndDate
from c
)
, e as (
select [ID.]
, [Status.]
, [Date.]
, BeginDate
, case when EndDate is null then lead(EndDate) over (order by [ID.], [Date.]) else EndDate end as EndDate
from d
)
select [ID.]
, [Status.]
, BeginDate as 'BeginDate.'
, EndDate
from e
where BeginDate is not null
order by [ID.]
, [Date.]
输出:
| ID. |
Status. |
BeginDate. |
ENDDate |
| Abc123 |
InActive |
2021-10-01 |
2021-10-02 |
| Abc123 |
Active |
2021-10-03 |
2021-10-05 |
| Abc123 |
InActive |
2021-10-06 |
2021-10-06 |
| Abc123 |
Active |
2021-10-07 |
2021-10-07 |
| Abc123 |
InActive |
2021-10-08 |
2021-10-09 |
| Def456 |
InActive |
2021-10-01 |
2021-10-02 |
| Def456 |
Active |
2021-10-03 |
2021-10-04 |