获取 T-SQL 中连续值的最大和最小日期
Get Max And Min dates for consecutive values in T-SQL
我有一个日志 table 如下所示,我想通过获取每个 ID 的连续状态值的最小开始日期和最大结束日期来简化它。我尝试了很多 window 函数组合,但没有成功。
这是我的:
这是想看的:
尝试以下查询。首先按StartDate对数据进行排序,生成一个序列(rid)。然后递归 cte 获取每个组 (id,status) 的第一行 (rid=1),然后递归获取下一行并比较 start/end 日期。
;WITH cte_r(id,[Status],StartDate,EndDate,rid)
AS
(
SELECT id,[Status],StartDate,EndDate, ROW_NUMBER() OVER(PARTITION BY Id,[Status] ORDER BY StartDate) AS rid
FROM log_table
),
cte_range(id,[Status],StartDate,EndDate,rid)
AS
(
SELECT id,[Status],StartDate,EndDate,rid
FROM cte_r
WHERE rid=1
UNION ALL
SELECT p.id, p.[Status], CASE WHEN c.StartDate<p.EndDate THEN p.StartDate ELSE c.StartDate END AS StartDate, c.EndDate,c.rid
FROM cte_range p
INNER JOIN cte_r c
ON p.id=c.id
AND p.[Status]=c.[Status]
AND p.rid+1=c.rid
)
SELECT id,[Status],StartDate,MAX(EndDate) AS EndDate FROM cte_range GROUP BY id,StartDate ;
这是一个典型的缺口孤岛问题。您想要聚合具有相同 Id
和 Status
的连续记录组。
不需要递归,这是使用window函数解决它的一种方法:
select
Id,
Status,
min(StartDate) StartDate,
max(EndDate) EndDate
from (
select
t.*,
row_number() over(partition by id order by StartDate) rn1,
row_number() over(partition by id, status order by StartDate) rn2
from mytable t
) t
group by
Id,
Status,
rn1 - rn2
order by Id, min(StartDate)
查询通过对两个不同分区(Id
和 Id
和 Status
上的记录进行排名来工作。等级之间的差异为您提供了每条记录所属的组。您可以 运行 独立地查看子查询 returns 并理解其逻辑。
Id | Status | StartDate | EndDate
-: | :----- | :------------------ | :------------------
1 | B | 07/02/2019 00:00:00 | 18/02/2019 00:00:00
1 | C | 18/02/2019 00:00:00 | 10/03/2019 00:00:00
1 | B | 10/03/2019 00:00:00 | 01/04/2019 00:00:00
2 | A | 05/02/2019 00:00:00 | 22/04/2019 00:00:00
2 | D | 22/04/2019 00:00:00 | 05/05/2019 00:00:00
2 | A | 05/05/2019 00:00:00 | 30/06/2019 00:00:00
我有一个日志 table 如下所示,我想通过获取每个 ID 的连续状态值的最小开始日期和最大结束日期来简化它。我尝试了很多 window 函数组合,但没有成功。
这是我的:
这是想看的:
尝试以下查询。首先按StartDate对数据进行排序,生成一个序列(rid)。然后递归 cte 获取每个组 (id,status) 的第一行 (rid=1),然后递归获取下一行并比较 start/end 日期。
;WITH cte_r(id,[Status],StartDate,EndDate,rid)
AS
(
SELECT id,[Status],StartDate,EndDate, ROW_NUMBER() OVER(PARTITION BY Id,[Status] ORDER BY StartDate) AS rid
FROM log_table
),
cte_range(id,[Status],StartDate,EndDate,rid)
AS
(
SELECT id,[Status],StartDate,EndDate,rid
FROM cte_r
WHERE rid=1
UNION ALL
SELECT p.id, p.[Status], CASE WHEN c.StartDate<p.EndDate THEN p.StartDate ELSE c.StartDate END AS StartDate, c.EndDate,c.rid
FROM cte_range p
INNER JOIN cte_r c
ON p.id=c.id
AND p.[Status]=c.[Status]
AND p.rid+1=c.rid
)
SELECT id,[Status],StartDate,MAX(EndDate) AS EndDate FROM cte_range GROUP BY id,StartDate ;
这是一个典型的缺口孤岛问题。您想要聚合具有相同 Id
和 Status
的连续记录组。
不需要递归,这是使用window函数解决它的一种方法:
select
Id,
Status,
min(StartDate) StartDate,
max(EndDate) EndDate
from (
select
t.*,
row_number() over(partition by id order by StartDate) rn1,
row_number() over(partition by id, status order by StartDate) rn2
from mytable t
) t
group by
Id,
Status,
rn1 - rn2
order by Id, min(StartDate)
查询通过对两个不同分区(Id
和 Id
和 Status
上的记录进行排名来工作。等级之间的差异为您提供了每条记录所属的组。您可以 运行 独立地查看子查询 returns 并理解其逻辑。
Id | Status | StartDate | EndDate -: | :----- | :------------------ | :------------------ 1 | B | 07/02/2019 00:00:00 | 18/02/2019 00:00:00 1 | C | 18/02/2019 00:00:00 | 10/03/2019 00:00:00 1 | B | 10/03/2019 00:00:00 | 01/04/2019 00:00:00 2 | A | 05/02/2019 00:00:00 | 22/04/2019 00:00:00 2 | D | 22/04/2019 00:00:00 | 05/05/2019 00:00:00 2 | A | 05/05/2019 00:00:00 | 30/06/2019 00:00:00