一分钟内传感器和温度值超过阈值时生成警报

时间:2020-03-01 07:05:59

标签: sql sql-server join cursor

考虑一个包含3列的表格:

  1. Timestamp:格式hh:mm:ss,每秒记录在表中
  2. PSI:每秒记录在表中的传感器值
  3. Temp:每秒在表中记录的温度值

我想编写一个查询,该查询何时会生成警报

  • 如果PSI大于60并且Temp大于255连续超过60秒或更长时间

例如如果PSI > 60 and Temp > 255的值从01:01:15到01:02:17,则应生成警报。

我尝试使用游标来完成这项工作,但是查询无法正常工作。有人可以帮助解决现有查询吗?另外,有人可以建议对此问题陈述进行替代且简单的查询吗?

我尝试过的查询:

declare @Timestamp time, @PSI int, @Temp int, @final_timestmp time, @status int 
set @final_timestmp='01:00:00'

declare cr_alert cursor for
    select Timestamp, PSI, Temp
    from [dbo].[Sensor_Values]
    where PSI > 60 and Temp > 255
    order by Timestamp

open cr_alert;

Fetch next from cr_alert into @Timestamp, @PSI, @Temp

while @@FETCH_STATUS = 0
begin
    set @status = 0
    print @status

    if (@Timestamp <> @final_timestmp)
    begin
        set @status = datediff(second, @final_timestmp, @Timestamp)

        if (@status = 1)
        begin
            set @final_timestmp = @Timestamp;

            insert into final_Sensor_Values 
                select @final_timestmp, @PSI, @Temp

            fetch next from cr_alert into @Timestamp, @PSI, @Temp
        end
    end
end

close cr_alert;
deallocate cr_alert;

样本数据集:

Timestamp   PSI Temp
01:01:01    59  264
01:01:02    63  247
01:01:03    56  245
01:01:04    64  262
01:01:05    50  245
01:01:06    57  244
01:01:07    64  251
01:01:08    60  259
01:01:09    52  244
01:01:10    52  242
01:01:11    63  259
01:01:12    56  241
01:01:13    51  252
01:01:14    52  261
01:01:15    50  265
01:01:16    54  251
01:01:17    59  243
01:01:18    64  240
01:01:19    55  265

或者您可以在以下网址中查看数据集。

https://i.stack.imgur.com/SGJlq.png

2 个答案:

答案 0 :(得分:0)

declare @t table
(
Timestamp time,
PSI smallint,
Temp smallint,
index clidx clustered(Timestamp)
--id int identity,
--primary key clustered(Timestamp, id)
);


insert into @t(Timestamp, PSI, Temp)
values
('01:01:01', 59, 264),
('01:01:02', 63, 247),
('01:01:03', 56, 245),
('01:01:04', 64, 262),
('01:01:05', 50, 245),
('01:01:06', 57, 244),
('01:01:07', 64, 251),
('01:01:08', 60, 259),
('01:01:09', 52, 244),
('01:01:10', 52, 242),
('01:01:11', 63, 259),
('01:01:12', 56, 241),
('01:01:13', 51, 252),
('01:01:14', 52, 261),
('01:01:15', 50, 265),
('01:01:16', 54, 251),
('01:01:17', 59, 243),
('01:01:18', 64, 240),
('01:01:19', 55, 265);

select *, case when l.totalrows = 5 and l.minPSI > 50 and l.minTemp > 240 then 1 else 0 end as AlertYN
from @t as t
cross apply
(
    select min(p.PSI) as minPSI, max(p.PSI) as maxPSI, min(p.Temp) as minTemp, max(p.Temp) as maxTemp, count(*) as totalrows
    from @t as p 
    where p.TimeStamp > dateadd(second, -5, t.TimeStamp) --check for last 5 secs
      and p.TimeStamp <= t.TimeStamp
) as l
--where l.minPSI > 50 and l.minTemp > 240

答案 1 :(得分:0)

假设每秒有一行,则可以使用窗口函数:

select sv.*,
       (case when min(temp) over (order by timestamp rows between 59 preceding and current row) > 255 and
                  min(PSI) over (order by timestamp rows between 59 preceding and current row) > 60
             then 'Alert!!!'
        end) as alert                  
from [dbo].[Sensor_Values] sv;

如果可能缺少几秒钟,则可以使用:

with sv as (
      select sv.*, row_number() over (order by timestamp) as seqnum
      from [dbo].[Sensor_Values] sv
     )
select sv.*,
       (case when min(temp) over (order by seqnum range between 59 preceding and current row) > 255 and
                  min(PSI) over (order by seqnum range between 59 preceding and current row) > 60
             then 'Alert!!!'
        end) as alert                  
from [dbo].[Sensor_Values] sv;

这里唯一的警告是,这可能会在数据开始时生成不必要的警报。