SQL 列值更改时重置 row_number

SQL Reset row_number when column value changed

我一直在尝试解决这个问题,但没有成功。我需要获取服务器不可用的持续时间。以下是数据

Date  |  Time  |  Address  |  Status
11-14 |  6:32  |  1.1.1.1  |  Down --- Count Start
11-14 |  6:34  |  1.1.1.1  |  Down
11-14 |  6:54  |  1.1.1.1  |  UP
11-14 |  7:20  |  1.1.1.1  |  Down --- Reset Count to 1
11-14 |  7:25  |  1.1.1.1  |  Down
11-14 |  7:30  |  1.1.1.1  |  Up
11-14 |  7:40  |  1.1.1.1  |  Down --- Reset Count to 1
11-14 |  6:35  |  2.2.2.2  |  Down --- Now this is a different counter cause of different IP

我有这个问题

SELECT [date]
  ,[time]
  ,[address]
  ,[ms]
  ,[bytes]
  ,[ttl]
  ,[Status]
  ,COALESCE(lag([Status]) over(order by [time]),'--') [Row]
  INTO #temp
FROM
(
SELECT [date]
  ,[time]
  ,[address]
  ,[ms]
  ,[bytes]
  ,[ttl]
  ,CASE WHEN [status] = 'Success' THEN 'UP' ELSE 'DOWN' END [Status]
 FROM [ESPS].[dbo].[Ping History] p
 INNER JOIN [SuperDashboard].[dbo].[IP_Mapping] i ON i.[IP] = p.address
 WHERE [Date] = CONVERT(Date,GETDATE())
) a

SELECT [date]
  ,[time]
  ,[address]
  ,[ms]
  ,[bytes]
  ,[ttl]
  ,[Status]
FROM
(
SELECT [date]
  ,[time]
  ,[address]
  ,[ms]
  ,[bytes]
  ,[ttl]
  ,[Status]
  ,CASE WHEN [Status] != [Row] THEN 1 ELSE 0 END [row]
FROM #temp
) a WHERE [row] = 1
DROP TABLE #temp

但这只适用于一个地址,因为当我尝试添加 2.2.2.2 时事情变得混乱了。理想的输出是每次遇到服务器停机时获取服务器停机的持续时间。我希望有人可以帮助我或至少为我指明正确的方向。

编辑 1:预期输出应为

Date  |  Start DownTime  |  End DownTime  | Address
11-14 |      6:32        |     6:54       | 1.1.1.1
11-14 |      7:20        |     7:30       | 1.1.1.1
11-14 |      7:40        |                | 1.1.1.1
11-14 |      6:35        |                | 2.2.2.2

使用 lag() 函数

DEMO

select *,case when stat='Down' and (prevval='Up' or prevval is null) then 1 else 0 end as val from
(
 select *,lag(stat) over(partition by address order by address) as prevval
 from #temp
)A

输出:

address stat    prevval val
1.1.1.1 Down            1
1.1.1.1 Up      Down    0
1.1.1.1 Down    Up      1
1.1.1.1 Down    Down    0
1.1.1.1 Up      Down    0
1.1.1.1 Down    Up      1
1.1.1.1 Down    Down    0
2.2.2.2 Down            1

这是一种 "group-and-islands" 问题。如果你能把所有的起伏和跟进(如果有的话)合并成一个组,那么剩下的就是聚合了。

并且,您可以通过计算每条记录上或之后出现的 UP 数来做到这一点。这是一个简单的累加和,然后剩下的就是聚合:

select address, date, grp,
       min(case when status = 'DOWN' then time end) as startDown,
       max(case when status = 'UP' then time end) as endUp
from (select t.*,
             sum(case when status = 'UP' then 1 else 0 end) over (partition by address, date order by time desc) as grp
      from t
     ) t
group by address, date, grp;