Jens Borrisholt
Jens Borrisholt

Reputation: 6402

Find a row after another row

The scope of this quesiton is SQL server 2016.

I have a table with some temperature measurements in. I'm trying to create a CTE with the 3 rows:

First row in the start of the process.

Second row when a threshold temperature is met.

Third row when another threshold temperature is met, but must be after the second row (order by time)

This is my SQL so far. It IS working, but finding the third rows seems a bit clumsy. Isn't there a smarter way to find it.

declare 
   @ThresholdMinTemp int = 550,  @ThresholdCoolingTemp int = 250;

declare @TestData Table
(
  Time int,
  Temp_Front int, 
  Temp_Center int, 
  Temp_Back int
);


insert into @TestData 
values 
    (2, 26, 27, 27), 
    (102, 26, 27, 27), 
    (232, 148, 136, 130), 
    (309, 252, 245, 238), 
    (548, 549, 553, 550), 
    (550, 550, 553, 550), 
    (552, 551, 554, 551), 
    (555, 552, 555, 552), 
    (722, 387, 387, 374), 
    (963, 250, 251, 233), 
    (967, 248, 249, 231);

with CTE_ResultTable  as
(
    select ROW_NUMBER() over (order by time) RowNumber, "Description", Time, Temp_Front,  Temp_Center, Temp_Back from 
     (      
        select  top 1 'Start temp' "Description", * from @TestData   order by time
        union all   
        select  top 1 'ThresholdMinTemp' "Description", * from @TestData  where Temp_Front >= @ThresholdMinTemp and Temp_Center >= @ThresholdMinTemp and Temp_Back >= @ThresholdMinTemp order by time
        union all 
        select  top 1 'ThresholdCoolingTemp' "Description", * from @TestData where Temp_Front <= @ThresholdCoolingTemp and Temp_Center <= @ThresholdCoolingTemp and Temp_Back <= @ThresholdCoolingTemp  
        and time > (select  top 1 time from TestData1 where Temp_Front >= @ThresholdMinTemp and Temp_Center >= @ThresholdMinTemp and Temp_Back >= @ThresholdMinTemp order by time)
        order by time
     ) Dummy
)
select * from CTE_ResultTable

So in short given the above dataset, I need to find the first row (order by time) where all 3 sensors measures max 250 degrees, after all three have reached 550 degrees!

In my real dataset I have a ID (uniqueidentifier) so if needed it can just be added to the demo dataset.

Upvotes: 1

Views: 98

Answers (2)

M Danish
M Danish

Reputation: 478

This may help.

declare @TestData Table
(
  Time int,
  Temp_Front int, 
  Temp_Center int, 
  Temp_Back int
);


insert into @TestData 
values 
    (2, 26, 27, 27), 
    (102, 26, 27, 27), 
    (232, 148, 136, 130), 
    (309, 252, 245, 238), 
    (548, 549, 553, 550), 
    (550, 550, 553, 550), 
    (552, 551, 554, 551), 
    (555, 552, 555, 552), 
    (722, 387, 387, 374), 
    (963, 250, 251, 233), 
    (967, 248, 249, 231);

WITH CTE_ResultTable (seq_no, Description, Time,Temp_Front, Temp_Center,Temp_Back)  
AS 

(

        select  top(1) 1 as seq_no, 'Start temp' "Description", Time,Temp_Front, Temp_Center, Temp_Back from @TestData   order by time
        union all   
        select  top(1) 2 as seq_no, 'ThresholdMinTemp' "Description", Time,Temp_Front, Temp_Center, Temp_Back from @TestData  where Temp_Front >= @ThresholdMinTemp and Temp_Center >= @ThresholdMinTemp and Temp_Back >= @ThresholdMinTemp order by time
        union all
        select  top(1) 3 as seq_no, 'ThresholdCoolingTemp' "Description",Time, Temp_Front, Temp_Center, Temp_Back from @TestData where Temp_Back <= @ThresholdCoolingTemp order by time desc


)
select * from CTE_ResultTable

Upvotes: 1

Thom A
Thom A

Reputation: 95620

If i understand correctly, this might be a "little" better; it at least doesn't scan the table 3 times (only the once).

WITH KPIs AS(
    SELECT *,
           CASE WHEN [Time] = MIN(Time) OVER () THEN 'Start Temp'
                WHEN Temp_Front >= @ThresholdMinTemp AND Temp_Center >= @ThresholdMinTemp AND Temp_Back >= @ThresholdMinTemp THEN 'ThresholdMinTemp' 
                WHEN Temp_Front <= @ThresholdCoolingTemp AND Temp_Center <= @ThresholdCoolingTemp AND Temp_Back <= @ThresholdCoolingTemp
                 AND COUNT(CASE WHEN Temp_Front >= @ThresholdMinTemp AND Temp_Center >= @ThresholdMinTemp AND Temp_Back >= @ThresholdMinTemp THEN 1 END) OVER (ORDER BY [Time] ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) > 1 THEN 'ThresholdCoolingTemp' END AS KPI
    FROM @TestData),
RNs AS (
    SELECT *,
           ROW_NUMBER() OVER (PARTITION BY KPI ORDER BY [time] ASC) AS RN
    FROM KPIs)
SELECT ROW_NUMBER() OVER (ORDER BY [Time]) AS RowNumber,
       KPI AS [Description],
       [Time],
       Temp_Front, Temp_Center, Temp_Back
FROM RNs
WHERE KPI IS NOT NULL
  AND RN = 1
ORDER BY RowNumber ASC;

Upvotes: 1

Related Questions