SQL 提取连续时间戳范围

问题描述 投票:0回答:1

表设备_状态

身份证 状态 时间戳
1 活跃 2023-01-13T18.00.01.0187528
2 活跃 2023-01-13T18.00.01.0187529
1 失败 2023-01-13T18.00.01.0187530
3 活跃 2023-01-13T18.00.01.0187531
1 失败 2023-01-13T18.00.01.0187532
1 活跃 2023-01-13T18.00.01.0187533
3 活跃 2023-01-13T18.00.01.0187534
1 失败 2023-01-13T18.00.01.0187535
4 失败 2023-01-13T18.00.01.0187536
1 活跃 2023-01-13T18.00.01.0187537

预期输出(需要SQL查询生成):

身份证 失败_开始 失败_结束
1 2023-01-13T18.00.01.0187530 2023-01-13T18.00.01.0187532
1 2023-01-13T18.00.01.0187535 2023-01-13T18.00.01.0187535
4 2023-01-13T18.00.01.0187536 2023-01-13T18.00.01.0187536

基本上,对于每个 ID 获取最小值(时间戳)和最大值(时间戳),但超过该 ID 的连续记录。如果只有一条记录,则与样本结果集中的第二条和第三条记录一样,min=max。

我已经尝试过这个(及其各种子查询变体)

SELECT Id, min(Timestamp) AS Fail_Begin, max(Timestamp) AS Fail_End
FROM Device_Status
GROUP BY Id

但需要仅按连续出现的记录进行分组,

那么也许首先添加状态更改的概念会有帮助?从零开始作为初始状态,然后每次下一条记录不同时将更改代码增加 1,以便生成像这样的中间结果...

表Device_Status_With_Change_Column

身份证 状态 改变 时间戳
1 活跃 0 2023-01-13T18.00.01.0187528
2 活跃 0 2023-01-13T18.00.01.0187529
1 失败 1 2023-01-13T18.00.01.0187530
3 活跃 0 2023-01-13T18.00.01.0187531
1 失败 1 2023-01-13T18.00.01.0187532
1 活跃 2 2023-01-13T18.00.01.0187533
3 活跃 0 2023-01-13T18.00.01.0187534
1 失败 3 2023-01-13T18.00.01.0187535
4 失败 0 2023-01-13T18.00.01.0187536
1 活跃 4 2023-01-13T18.00.01.0187537

然后做

SELECT Id, Change, min(Timestamp) AS Fail_Begin, max(Timestamp) AS Fail_End
FROM Device_Status_With_Change_Column
GROUP BY Id, Change

除了用编程语言循环结果集之外,我还没有看到直接的 SQL 语句可以在没有中间表的情况下一次性完成此操作,并且我没有看到如何计算列 Change(在 SQL 中)。

sql loops join subquery sql-timestamp
1个回答
0
投票

下面的解决方案首先使用子查询将行号与每个

failed
记录关联起来,该行号由每个
id
块进行分区。然后,子查询被
join
变为自身:

with cte as (
   select row_number() over (partition by t.id order by t.timestamp) r, t.* from device_status t where t.status = 'Failed'
)
select c.id, c.timestamp fail_start, coalesce(c1.timestamp, c.timestamp) fail_end
from cte c join cte c1 on c.id = c1.id and c.r + 1 = c1.r
where c.r % 2 = 1

看小提琴

© www.soinside.com 2019 - 2024. All rights reserved.