我在SQL db(HeartbeatHistory)
中有下表Timestamp | Comment | Id
------------------------
评论可以包含OK或ERR
Id是具有该评论的内容的ID。
我希望能够查询表并找到任何给定id处于错误状态的持续时间。
Timestamp | Comment | Id
------------------------
12:00:00 | OK | 1
11:59:00 | ERR | 2
11:58:00 | OK | 4
11:57:00 | OK | 3
11:45:00 | ERR | 4
11:20:00 | OK | 2
11:00:00 | ERR | 3
11:30:00 | OK | 5
11:20:00 | ERR | 1
11:10:00 | OK | 1
11:00:00 | ERR | 1
10:30:00 | ERR | 5
所以在上表中如果我查询11:00:00到13:00:00我想看看。
ErrorStart | ErrorEnd | Id
--------------------------
11:00:00 | 11:10:00 | 1
11:20:00 | 12:00:00 | 1
11:59:00 | 12:00:00 | 2
11:00:00 | 11:57:00 | 3
11:45:00 | 11:58:00 | 4
11:00:00 | 11:30:00 | 5
(通知5在查询日期之前启动错误!!)
这可能吗?此外,Id可能会在查询期间多次更改状态。
到目前为止,我有这个,适用于单个ID,但我需要让它适用于多个ID。
declare @startDate datetime = @from;
declare @endDate datetime = @to;
declare @kpiId = 1;
select Foo.RowCreatedTimestamp, Foo.Comment, Foo.NextTimeStamp, Foo.NextComment, Foo.HeartBeatId, Foo.NextHeartBeatId
from (
select RowCreatedTimestamp, Comment,
lag(RowCreatedTimestamp, 1, 0) over (order by RowCreatedTimestamp desc) as NextTimeStamp,
lag(Comment, 1, 0) over (order by RowCreatedTimestamp desc) as NextComment,
HeartBeatId
from dbo.tblHeartbeatHistory
where RowCreatedTimestamp >= @startDate and RowCreatedTimestamp <= @endDate
and HeartbeatId in
(
select HeartbeatId
from dbo.tblKpiHeartBeats
where KpiId = @kpiId
)
) as Foo
where Foo.Comment like '%set to ERR%'
order by Foo.RowCreatedTimestamp desc;
因此,如果select HeartbeatId from dbo.tblKpiHeartBeats
返回单个Id,则可行。只要他们有多个身份证,就不会:(
为避免混淆:
带有Timestamp,Comment和Id的表是HeartbeatHistory。
我的SQL中引用的另一个表是dbo.tblKpiHeartBeats。
此表格如下:
Kpi | HeartbeatId
-----------------
1 | 1
1 | 2
1 | 3
1 | 4
1 | 5
所以我希望Kpi = 1的所有错误间隔,它将返回HeartbeatId 1,2,3,4和5的错误间隔。
进一步说明。在确定进入之前,数据可能会连续出现多个错误。
查询期间可能只是所有ERR,或者一切正常。
答案 0 :(得分:2)
您可以添加第二个CTE ID,您希望完全加入ERR和OK行(以下代码仅适用于OK行)
WIRH History AS (
SELECT
FROM HeartbeatHistory
WHERE Timestamp BETWEEN @DateStart AND @DateEnd
), Errors AS(
SELECT Id, MIN(Timestamp) AS ErrorStart
FROM History
WHERE Comment = 'ERR'
GROUP BY Id
)
SELECT
ErrorStart = E.ErrorStart ,
ErrorEnd = O.Timestamp,
Id = O.Id
FROM History O
LEFT JOIN Errors E ON E.Id = O.Id
WHERE O.Comment = 'OK'
编辑:您可以将prevOK timespan(或PK)列添加到表中(可能是计算持久性) - 链接到最后一个好行。它将在报告中用作行的ID。
试试这个索引:
CREATE INDEX IDX_EXAMPLE ON HeartbeatHistory (Timestamp, Id, prevOK, Comment)
WIRH History AS (
SELECT
FROM HeartbeatHistory
WHERE Timestamp BETWEEN @DateStart AND @DateEnd
)
SELECT
ErrorStart = E.ErrorStart ,
ErrorEnd = O.Timestamp,
Id = O.Id
FROM History O
OUTER APPLY (
SELECT MIN(Timestamp) AS ErrorStart
FROM History E
WHERE E.Id = O.ID AND E.prevOK = O.prevOK
)
WHERE O.Comment = 'OK'
答案 1 :(得分:0)
最简单的方法是使用lead()
。如果我假设ERR
连续两次没有出现(如示例数据中所示):
select (case when timestamp >= '11:00:00' then timestamp else '11:00:00' end) as errorStart,
(case when next_timestamp <= '13:00:00' then next_timestamp else '13:00:00') as errorEnd,
id
from (select t.*,
lead(timestamp) over (partition by id order by timestamp) as next_timestamp
from t
) t
where comment = 'ERR' and
(timestamp <= '13:00:00' and
(next_timestamp >= '11:00:00' or next_timestamp is null)
);
答案 2 :(得分:0)
试试这个:
DECLARE @table TABLE (Timestmp TIME(1), Comment NVARCHAR(5), Id INT) --your table
INSERT INTO @table VALUES
('12:00:00','OK ','1'),('11:59:00','ERR','2'),('11:58:00','OK ','4'),('11:57:00','OK ','3'),
('11:45:00','ERR','4'),('11:20:00','OK ','2'),('11:00:00','ERR','3'),('11:30:00','OK ','5'),
('11:20:00','ERR','1'),('11:10:00','OK ','1'),('11:00:00','ERR','1'),('10:30:00','ERR','5')
DECLARE @ROWER TABLE (id INT IDENTITY(1,1), Timestmp TIME(1))
INSERT INTO @ROWER SELECT Timestmp FROM @table WHERE Comment='OK' ORDER BY Timestmp
DECLARE @TIME TIME(1) = '11:00:00' --your condition
SELECT DISTINCT CASE WHEN A.Timestmp >=@TIME THEN A.Timestmp ELSE @TIME END ErrorStart,
CASE WHEN B.Timestmp > A.Timestmp THEN B.Timestmp ELSE '' END ErrorEnd,
A.Id FROM (
SELECT ROW_NUMBER() OVER (ORDER BY id,Timestmp) rowid,* FROM @table WHERE Comment = 'ERR'
) A LEFT JOIN (
SELECT ROW_NUMBER() OVER (ORDER BY id,Timestmp) rowid,* FROM @table WHERE Comment = 'OK'
) B ON A.rowid = B.rowid
LEFT JOIN ( SELECT A.id,A.Timestmp t1,B.Timestmp t2 FROM @ROWER A
LEFT JOIN (SELECT id-1 id, Timestmp FROM @ROWER) B ON A.id=B.id
) C ON A.Timestmp BETWEEN C.t1 AND C.t2 ORDER BY A.Id
希望它有所帮助。 :)