时间跨度计算
Timespan calculation
我有一个 table 这样的:
#Row ID Status1 Status2 TimeStatusChange
------------------------------------------
1 24 0 0 2020-09-02 09:18:02.233
2 48 0 0 2020-09-02 09:18:58.540
3 24 1 0 2020-09-02 09:19:47.233
4 24 0 0 2020-09-02 09:19:47.587
5 48 0 1 2020-09-02 09:22:53.923
6 36 1 0 2020-09-02 09:24:14.343
7 48 0 0 2020-09-02 09:24:49.670
8 24 1 0 2020-09-02 09:38:37.820
并且想知道,如何计算所有状态(1 或 2)从 0 到 1(或 1 到 0)按 ID 分组的时间跨度总和。
在此示例中,对于 ID 24,Status1 从 0 到 1,这将是#Row 3 和#row 1 的 TimeStatusChange 的差异 + #Row 8 和#row 4 的 TimeStatusChange 的差异,大约 21 分钟。
完美的输出应该是这样的:
ID Change TimeSpanInMinutes
----------------------------------------
24 Status1_from_0_1 20
36 .....
虽然我有一些使用 PL/SQL 的经验,但我一无所获。
示例数据
我添加了几行以获得更多结果数据,并验证了给定 ID 存在具有相同状态的连续行的场景。
declare @data table
(
ID int,
Status1 int,
Stamp datetime
)
insert into @data (ID, Status1, Stamp) values
(48, 1, '2020-09-02 09:00:00.000'), --added row
(24, 0, '2020-09-02 09:18:02.233'),
(48, 0, '2020-09-02 09:18:58.540'),
(24, 1, '2020-09-02 09:19:47.233'),
(24, 0, '2020-09-02 09:19:47.587'),
(48, 0, '2020-09-02 09:22:53.923'),
(36, 1, '2020-09-02 09:24:14.343'),
(48, 0, '2020-09-02 09:24:49.670'),
(24, 1, '2020-09-02 09:38:37.820'),
(48, 1, '2020-09-02 10:00:00.000'); --added row
解决方案
在lag()函数的帮助下,使用通用的table表达式(CTE,cte_data
)获取同一ID的前一条记录(无论其状态值如何) .在 CTE 外部的 where
子句中删除与前一行具有相同值的后续行。
with cte_data as
(
select d.ID,
d.Status1,
d.Stamp,
lag(d.Status1) over(partition by d.ID order by d.Stamp) as Status1Prev,
lag(d.Stamp) over(partition by d.ID order by d.Stamp) as StampPrev
from @data d
)
select d.ID,
d.Status1Prev as Status1From,
d.Status1 as Status1To,
sum(datediff(MI, d.StampPrev, d.Stamp)) as StampDiffSumM, --minutes
convert(time(3), dateadd(MS, sum(datediff(MS, d.StampPrev, d.Stamp)), '1900-01-01 00:00:00.000')) as StampDiffSumF --formatted
from cte_data d
where d.Status1 <> d.Status1Prev
and d.Status1Prev is not null
group by d.ID, d.Status1Prev, d.Status1
order by d.ID;
结果
ID Status1From Status1To StampDiffSumM StampDiffSumF
----------- ----------- ----------- ------------- ----------------
24 0 1 20 00:20:35.233
24 1 0 0 00:00:00.353
48 0 1 36 00:35:10.330
48 1 0 18 00:18:58.540
我有一个 table 这样的:
#Row ID Status1 Status2 TimeStatusChange
------------------------------------------
1 24 0 0 2020-09-02 09:18:02.233
2 48 0 0 2020-09-02 09:18:58.540
3 24 1 0 2020-09-02 09:19:47.233
4 24 0 0 2020-09-02 09:19:47.587
5 48 0 1 2020-09-02 09:22:53.923
6 36 1 0 2020-09-02 09:24:14.343
7 48 0 0 2020-09-02 09:24:49.670
8 24 1 0 2020-09-02 09:38:37.820
并且想知道,如何计算所有状态(1 或 2)从 0 到 1(或 1 到 0)按 ID 分组的时间跨度总和。
在此示例中,对于 ID 24,Status1 从 0 到 1,这将是#Row 3 和#row 1 的 TimeStatusChange 的差异 + #Row 8 和#row 4 的 TimeStatusChange 的差异,大约 21 分钟。
完美的输出应该是这样的:
ID Change TimeSpanInMinutes
----------------------------------------
24 Status1_from_0_1 20
36 .....
虽然我有一些使用 PL/SQL 的经验,但我一无所获。
示例数据
我添加了几行以获得更多结果数据,并验证了给定 ID 存在具有相同状态的连续行的场景。
declare @data table
(
ID int,
Status1 int,
Stamp datetime
)
insert into @data (ID, Status1, Stamp) values
(48, 1, '2020-09-02 09:00:00.000'), --added row
(24, 0, '2020-09-02 09:18:02.233'),
(48, 0, '2020-09-02 09:18:58.540'),
(24, 1, '2020-09-02 09:19:47.233'),
(24, 0, '2020-09-02 09:19:47.587'),
(48, 0, '2020-09-02 09:22:53.923'),
(36, 1, '2020-09-02 09:24:14.343'),
(48, 0, '2020-09-02 09:24:49.670'),
(24, 1, '2020-09-02 09:38:37.820'),
(48, 1, '2020-09-02 10:00:00.000'); --added row
解决方案
在lag()函数的帮助下,使用通用的table表达式(CTE,cte_data
)获取同一ID的前一条记录(无论其状态值如何) .在 CTE 外部的 where
子句中删除与前一行具有相同值的后续行。
with cte_data as
(
select d.ID,
d.Status1,
d.Stamp,
lag(d.Status1) over(partition by d.ID order by d.Stamp) as Status1Prev,
lag(d.Stamp) over(partition by d.ID order by d.Stamp) as StampPrev
from @data d
)
select d.ID,
d.Status1Prev as Status1From,
d.Status1 as Status1To,
sum(datediff(MI, d.StampPrev, d.Stamp)) as StampDiffSumM, --minutes
convert(time(3), dateadd(MS, sum(datediff(MS, d.StampPrev, d.Stamp)), '1900-01-01 00:00:00.000')) as StampDiffSumF --formatted
from cte_data d
where d.Status1 <> d.Status1Prev
and d.Status1Prev is not null
group by d.ID, d.Status1Prev, d.Status1
order by d.ID;
结果
ID Status1From Status1To StampDiffSumM StampDiffSumF
----------- ----------- ----------- ------------- ----------------
24 0 1 20 00:20:35.233
24 1 0 0 00:00:00.353
48 0 1 36 00:35:10.330
48 1 0 18 00:18:58.540