2013-08-02 1 views
2

Предположим, у меня есть таблица, содержащая набор точек данных, каждый из которых состоит из метки времени и значения. Как написать запрос, который возвращает true (1), если есть по меньшей мере N последовательных записей (упорядоченных по метке времени), которые превышают заданное значение X, false (0) в противном случае?Значение порога для n последовательных минут

Следующая делает это в течение 3 последовательных записей, но не работает в общем случае без создания динамического запроса и добавить больше «и существует» случаи:

truncate table tblData 
insert into tblData values ('1-jul-2013 13:01:00', 64) 
insert into tblData values ('1-jul-2013 13:02:00', 13) 
insert into tblData values ('1-jul-2013 13:03:00', 7) 
insert into tblData values ('1-jul-2013 13:04:00', 17) 
insert into tblData values ('1-jul-2013 13:05:00', 7) 
insert into tblData values ('1-jul-2013 13:06:00', 18) 
insert into tblData values ('1-jul-2013 13:07:00', 9) 
insert into tblData values ('1-jul-2013 13:08:00', 20) 
insert into tblData values ('1-jul-2013 13:09:00', 12) 
insert into tblData values ('1-jul-2013 13:10:00', 21) 
insert into tblData values ('1-jul-2013 13:11:00', 22) 
insert into tblData values ('1-jul-2013 13:12:00', 3) 
insert into tblData values ('1-jul-2013 13:13:00', 22) 
insert into tblData values ('1-jul-2013 13:14:00', 20) 

declare @x as int = 10 

select count(*) 
from tblData a 
where a.dt in 
(select dt from tblData b where b.value > @x and b.dt >= a.dt and b.dt < DATEADD(minute,1,a.dt)) and exists 
(select dt from tblData b where b.value > @x and b.dt >= DATEADD(minute,1,a.dt) and b.dt < DATEADD(minute,2,a.dt)) and exists 
(select dt from tblData b where b.value > @x and b.dt >= DATEADD(minute,2,a.dt) and b.dt < DATEADD(minute,3,a.dt)) 

Идеи?

+0

гарантированную ли каждая метка времени, чтобы быть на минуту? –

ответ

3

В принципе, вы хотите получить суммарную сумму флага, говорящего, что столбец превышает значение @x.

Оказалось, что вы можете сделать это с помощью некоторых трюков, используя row_number(). Перечислите все строки, используя row_number() (в заказе времени). Затем перечислите все строки, разбив их на флаг. Разница между ними будет постоянной, которая идентифицирует группу последовательных строк. Затем, с агрегацией, мы можем получить наибольшую длину последовательных значений, где флаг истинно (или ложно):

select seqnum - seqnum_flag, count(*) 
from (select d.*, 
      row_number() over (order by dt) as seqnum, 
      row_number() over (partition by (case when val > @x then 1 else 0 end) 
           order by dt) as seqnum_flag 
     from tblData d 
    ) d 
where val > @x 
group by (seqnum - seqnum_flag); 

Это возвращает каждую последовательность и длину его. Это должно дать вам информацию, необходимую для продолжения.

Вы можете посмотреть, как это работает SQL Fiddle.

+0

Я сделал так далеко, что придумал таблицу флагов, но все еще не был уверен, как считать последовательные 1. Отличный запрос, спасибо. – Dan

0

Вы можете использовать предложение over ... rows N preceding, чтобы рассчитать минимум за последние N строк. Например, это показывает 1, если эта строка и последние 3 строки имеют значение больше, чем 10:

select * 
,  case when min(val) over (order by dt rows 3 preceding) > 10 then 1 else 0 end 
from tblData 

Example at SQL Fiddle.

+0

. , Я не думаю, что этот синтаксис поддерживается в SQL Server 2008. Это произошло в 2012 году. –

+0

@GordonLinoff: Да, это определенно синтаксис 2012 года – Andomar

Смежные вопросы