T-SQL для получения последовательных строк - PullRequest
0 голосов
/ 23 января 2019

Я пытаюсь написать запрос, который выдаст все SensorID и LocID, которые имеют пять последовательных datetime строк, т.е. разница между ними составляет 1 час, а напряжение> = 6. Я могу использовать LAG и получить разницу в минутах, но как выбрать последовательные строки?

Таблица ввода:

SensorID LocID DateTime Voltage
-------------------------------
    100 200 1/23/2019 13:00 6 
    100 200 1/23/2019 12:00 8
    100 200 1/23/2019 11:00 6
    100 200 1/23/2019 10:00 7
    100 200 1/23/2019 9:00 8
    101 201 1/23/2019 10:00 8
    101 201 1/23/2019 9:00 1
    101 201 1/23/2019 8:00 2
    101 201 1/23/2019 6:00 8
    101 201 1/23/2019 5:00 1
    103 203 1/23/2019 11:00 10
    103 203 1/23/2019 10:00 11
    103 203 1/23/2019 9:00 8
    103 203 1/23/2019 8:00 9
    103 203 1/23/2019 7:00 9

Требуемый вывод:

SensorID LocID DateTime Voltage
-------------------------------
    100 200 01/23/19 1 PM 6
    100 200 01/23/19 12 PM  8
    100 200 01/23/19 11 AM  6
    100 200 01/23/19 10 AM  7
    100 200 01/23/19 9 AM 8
    103 203 01/23/19 11 AM  10
    103 203 01/23/19 10 AM  11
    103 203 01/23/19 9 AM 8
    103 203 01/23/19 8 AM 9
    103 203 01/23/19 7 AM 9

use tempdb
go

Create Table #Input
(
    SensorID int
    , LocID int
    , DateTime datetime 
    , Voltage float
)

Insert Into #Input
Select 100,200,'1/23/2019 13:00',6 Union All
Select 100,200,'1/23/2019 12:00',8 Union All
select 100,200,'1/23/2019 11:00',6 Union All
Select 100,200,'1/23/2019 10:00',7 Union All
Select 100,200,'1/23/2019 9:00',8 Union All
Select 101,201,'1/23/2019 10:00',8 Union All
Select 101,201,'1/23/2019 9:00',1 Union All
Select 101,201,'1/23/2019 8:00',2 Union All
Select 101,201,'1/23/2019 6:00',8 Union All
Select 101,201,'1/23/2019 5:00',1 Union All
Select 103,203,'1/23/2019 11:00',10 Union All
Select 103,203,'1/23/2019 10:00',11 Union All
Select 103,203,'1/23/2019 9:00',8 Union All
Select 103,203,'1/23/2019 8:00',9 Union All
Select 103,203,'1/23/2019 7:00',9

Select * from #Input

drop table #Input
go

1 Ответ

0 голосов
/ 23 января 2019

Вы можете использовать аргумент OFFSET, равный LAG, чтобы проверить 4 строки назад, чтобы сделать ее 5-строчным окном (считая текущий). Например: lag(Column,Offset,Default) где столбец - это столбец, смещение - это количество строк назад, а значение по умолчанию - это то, что возвращается в случае сбоя условия (NULL по умолчанию).

;with cte as(
select 
    * 
    ,LogicCheck = abs(datediff(hour,[DateTime],lag([DateTime],4) over (partition by SensorID order by [DateTime])))
from #Input
)

select *
from #Input
where SensorID in (select SensorID from cte where LogicCheck = 4)

Это работает с вашими примерами данных, но если есть большие окна, вы должны учитывать это. См. Этот дополнительный пример данных и метод для ухода за большими окнами.

use tempdb
go
Create Table #Input
(
    SensorID int
    , LocID int
    , DateTime datetime 
    , Voltage float
)

Insert Into #Input
Select 100,200,'1/23/2019 13:00',6 Union All
Select 100,200,'1/23/2019 12:00',8 Union All
select 100,200,'1/23/2019 11:00',6 Union All
Select 100,200,'1/23/2019 10:00',7 Union All
Select 100,200,'1/23/2019 9:00',8 Union All
Select 101,201,'1/23/2019 10:00',8 Union All
Select 101,201,'1/23/2019 9:00',1 Union All
Select 101,201,'1/23/2019 8:00',2 Union All
Select 101,201,'1/23/2019 6:00',8 Union All
Select 101,201,'1/23/2019 5:00',1 Union All
Select 103,203,'1/23/2019 11:00',10 Union All
Select 103,203,'1/23/2019 10:00',11 Union All
Select 103,203,'1/23/2019 9:00',8 Union All
Select 103,203,'1/23/2019 8:00',9 Union All
Select 103,203,'1/23/2019 7:00',9 Union All
Select 103,203,'1/23/2019 6:00',9 Union all --added this row which should be included
Select 103,203,'1/23/2019 4:00',9           --added this row which is a break in the time and shouldn't be returned



;with cte as(
select 
    * 
    ,Seq = row_number() over (partition by SensorID order by [DateTime])
    ,LogicCheck = abs(datediff(hour,[DateTime],lag([DateTime],4) over (partition by SensorID order by [DateTime])))
from #Input
)

select
    c.SensorID
    ,c.LocID
    ,c.DateTime
    ,c.Voltage
    --,c.Seq
    --,c.LogicCheck
from    
    cte c
where exists
    (
        select SensorID
        from cte 
        where LogicCheck = 4
        and cte.SensorID = c.SensorID
        and c.Seq <= cte.Seq
        and c.Seq >= cte.Seq - 4
    )



drop table #Input
...