简体   繁体   中英

T-SQL to get consecutive Rows

I'm trying to write a query that will give all the SensorID and LocID that have five consecutive datetime rows, ie the difference between them is 1 hour and voltage is >= 6. I can use LAG and get the difference in minutes, but how to select the consecutive rows?

Input table:

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

Required output:

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

You can use the OFFSET argument of LAG to check 4 rows back to make it a 5 row window (counting the current). EG: lag(Column,Offset,Default) where column is the column, offset is the number of rows back, and default is what to return if the condition fails ( NULL by default).

;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)

This works with your sample data but if there are larger windows, you'll want to account for that. See this added sample data and method for taking care of the larger windows.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM