动态计算同一行的时间差
Calculate the time difference in the same row dynamically
是否有任何方法可以根据 'DOWN' 和 'UP' 值计算同一列中行之间 SQL 的时间差,如下所示:
有 3 种情况(我知道):
- 黄橙绿:有一个state_id2(down),后面有一个state_id5(up),所以需要计算两行的时间差;
- 蓝色:有多个state_id2(down),后面有一个state_id5(up),所以需要计算第一行和最后一行的时间差;
- 红色:只有一个state_id2(down),因为任何更新都还是down,所以要计算到月底的时差
希望你能帮帮我。
我之前的做法是
Select a.state_time as downtime,
(
select min(inner.state_time) from tablename downentry where
inner.state_time > outer.state_time and downentry.state='UP'
) as uptime
from tablename upentry
where state = 'DOWN'
然后你需要找到它们之间的datediff,如果uptime为null,则downtime和'endofmonth'
之间的datediff
它的性能可能很差,所以我总是将答案写到数据仓库中,但我认为它会给出您要求的结果。
首先考虑为此使用 LAG。
但是使用累积 SUM,MIN 的 window 版本也适用于超过 2 个 DOWN:
-- test reference data
declare @State table (id int, state varchar(4));
insert into @State (id, state) values
(2,'DOWN'),
(5,'UP')
-- test data, using a table variable
declare @AlertState table (alert_id int identity(1,1), host_id int, state_time datetime, state_id int);
insert into @AlertState (host_id, state_time, state_id) values
(119, GetDate()-0.32, 2),
(119, GetDate()-0.31, 5),
(119, GetDate()-0.24, 2),
(119, GetDate()-0.23, 2),
(119, GetDate()-0.22, 2),
(119, GetDate()-0.21, 5),
(119, GetDate()-0.15, 5),
(119, GetDate()-0.11, 2);
-- The query
select alert_id, host_id, state_time, state_id,
diff_min = (
case
when state_id = 5 then
datediff(minute, min(state_time) over (partition by host_id, stategroup), state_time)
when state_id = 2 and stategroup is null then
datediff(minute, state_time, cast(EOMONTH(GetDate()) as datetime)+1)
end),
s.state
from (
select alert_id, host_id, state_time, state_id,
sum(case state_id when 5 then 1 end) over (partition by host_id order by state_time desc) as stategroup
from @AlertState
where state_id in (2,5)
) q
left join @State s on s.id = q.state_id
order by state_time, alert_id;
SQL2012+
您可以尝试以下解决方案:
SELECT y.group_id, host_id = MIN(host_id), start_time = MIN(state_time), end_time = MAX(state_time), diff_minute = DATEDIFF(MINUTE, MIN(state_time), MAX(state_time))
FROM (
SELECT *, group_id = SUM(x.new_group_start) OVER(ORDER BY x.host_id, x.state_time)
FROM (
SELECT *, new_group_start = IIF(a.state_id = 'DOWN' AND ISNULL(LAG(a.state_id) OVER(ORDER BY a.host_id, a.state_time), 'UP') = 'UP', 1, 0)
FROM @Alerts a
) x
) y
GROUP BY y.group_id
ORDER BY y.group_id
是否有任何方法可以根据 'DOWN' 和 'UP' 值计算同一列中行之间 SQL 的时间差,如下所示:
有 3 种情况(我知道):
- 黄橙绿:有一个state_id2(down),后面有一个state_id5(up),所以需要计算两行的时间差;
- 蓝色:有多个state_id2(down),后面有一个state_id5(up),所以需要计算第一行和最后一行的时间差;
- 红色:只有一个state_id2(down),因为任何更新都还是down,所以要计算到月底的时差
希望你能帮帮我。
我之前的做法是
Select a.state_time as downtime,
(
select min(inner.state_time) from tablename downentry where
inner.state_time > outer.state_time and downentry.state='UP'
) as uptime
from tablename upentry
where state = 'DOWN'
然后你需要找到它们之间的datediff,如果uptime为null,则downtime和'endofmonth'
之间的datediff它的性能可能很差,所以我总是将答案写到数据仓库中,但我认为它会给出您要求的结果。
首先考虑为此使用 LAG。
但是使用累积 SUM,MIN 的 window 版本也适用于超过 2 个 DOWN:
-- test reference data
declare @State table (id int, state varchar(4));
insert into @State (id, state) values
(2,'DOWN'),
(5,'UP')
-- test data, using a table variable
declare @AlertState table (alert_id int identity(1,1), host_id int, state_time datetime, state_id int);
insert into @AlertState (host_id, state_time, state_id) values
(119, GetDate()-0.32, 2),
(119, GetDate()-0.31, 5),
(119, GetDate()-0.24, 2),
(119, GetDate()-0.23, 2),
(119, GetDate()-0.22, 2),
(119, GetDate()-0.21, 5),
(119, GetDate()-0.15, 5),
(119, GetDate()-0.11, 2);
-- The query
select alert_id, host_id, state_time, state_id,
diff_min = (
case
when state_id = 5 then
datediff(minute, min(state_time) over (partition by host_id, stategroup), state_time)
when state_id = 2 and stategroup is null then
datediff(minute, state_time, cast(EOMONTH(GetDate()) as datetime)+1)
end),
s.state
from (
select alert_id, host_id, state_time, state_id,
sum(case state_id when 5 then 1 end) over (partition by host_id order by state_time desc) as stategroup
from @AlertState
where state_id in (2,5)
) q
left join @State s on s.id = q.state_id
order by state_time, alert_id;
SQL2012+
您可以尝试以下解决方案:
SELECT y.group_id, host_id = MIN(host_id), start_time = MIN(state_time), end_time = MAX(state_time), diff_minute = DATEDIFF(MINUTE, MIN(state_time), MAX(state_time))
FROM (
SELECT *, group_id = SUM(x.new_group_start) OVER(ORDER BY x.host_id, x.state_time)
FROM (
SELECT *, new_group_start = IIF(a.state_id = 'DOWN' AND ISNULL(LAG(a.state_id) OVER(ORDER BY a.host_id, a.state_time), 'UP') = 'UP', 1, 0)
FROM @Alerts a
) x
) y
GROUP BY y.group_id
ORDER BY y.group_id