Please start any new threads on our new site at https://forums.sqlteam.com. We've got lots of great SQL Server experts to answer whatever question you can come up with.

 All Forums
 SQL Server 2012 Forums
 Transact-SQL (2012)
 find last local maximum in a time series

Author  Topic 

jezemine
Master Smack Fu Yak Hacker

2886 Posts

Posted - 2013-05-28 : 13:32:04
I have some timeseries data and need to find the "last" local maximum in the series when ordered by time. Here's a sample to show what I mean:


declare @t table (time_key int not null primary key, val int not null)

-- easy case. here the last max is just the time_key
-- when val=max(val), because there is only one max
insert @t (time_key,val) values (1,100)
insert @t (time_key,val) values (2,101)
insert @t (time_key,val) values (3,106)
insert @t (time_key,val) values (4,120)
insert @t (time_key,val) values (5,130)
insert @t (time_key,val) values (6,140) -- this is the first and last max, so desired result is time_key=6
insert @t (time_key,val) values (7,130)
insert @t (time_key,val) values (8,120)
insert @t (time_key,val) values (9,110)
insert @t (time_key,val) values (10,100)
insert @t (time_key,val) values (11,90)

select * from @t
go

declare @t table (time_key int not null primary key, val int not null)

-- hard case - here the time for the last max is time_key=13, because that's the time where afterwards, val never increased.
insert @t (time_key,val) values (1,100)
insert @t (time_key,val) values (2,101)
insert @t (time_key,val) values (3,130) -- first max
insert @t (time_key,val) values (4,120)
insert @t (time_key,val) values (5,130)
insert @t (time_key,val) values (6,140)
insert @t (time_key,val) values (7,150) -- second max
insert @t (time_key,val) values (8,140)
insert @t (time_key,val) values (9,130)
insert @t (time_key,val) values (10,120)
insert @t (time_key,val) values (11,110)
insert @t (time_key,val) values (12,100)
insert @t (time_key,val) values (13,110) -- this is the last max, so the desired result is time_key=13
insert @t (time_key,val) values (14,100)
insert @t (time_key,val) values (15,90)
insert @t (time_key,val) values (16,80)

select * from @t
go


Desired result is a query to give me time_key=6 for the first set of sample data, and time_key=13 for the second set.

This would be easy to do in procedural code, but I am stumped on coming up with a set-based way to do it.

It's not just a simple max() query because I need the time of the last local maximum, and the last local max will not be a global max in general. In the first sample it's a global max but that's only because there was only one max in that case.

In the second example, there are 3 maxima, I want the time of the "last" one.

thanks!


elsasoft.org

Lamprey
Master Smack Fu Yak Hacker

4614 Posts

Posted - 2013-05-28 : 13:50:07
Can you describe the logic in words? How do you define/determine a "max?"
Go to Top of Page

visakh16
Very Important crosS Applying yaK Herder

52326 Posts

Posted - 2013-05-28 : 14:46:47
[code]
SELECT TOP 1 time_key
FROM
(
SELECT *,LAG(val,1,0) OVER (ORDER BY time_key) AS lastVal,LEAD(val,1,0) OVER (ORDER BY time_key) AS NextVal
FROM @t
)t
WHERE val > LastVal AND val > NextVal
ORDER BY time_key DESC
[/code]

------------------------------------------------------------------------------------------------------
SQL Server MVP
http://visakhm.blogspot.com/
https://www.facebook.com/VmBlogs
Go to Top of Page

visakh16
Very Important crosS Applying yaK Herder

52326 Posts

Posted - 2013-05-28 : 14:50:25
I posted a 2012 based solution as you posted this in 2012 forum

If earlier version you need this

;With CTE
AS
(
SELECT ROW_NUMBER() OVER (ORDER BY time_key) AS rn,time_key,val
FROM @t
)

SELECT TOP 1 c1.time_key
FROM CTE c1
INNER JOIN CTE c2
ON c2.Rn = c1.Rn-1
INNER JOIN CTE c3
ON c3.Rn = c1.Rn + 1
WHERE c1.val > c2.Val
AND c1.val > c3.Val
ORDER BY c1.time_key DESC


------------------------------------------------------------------------------------------------------
SQL Server MVP
http://visakhm.blogspot.com/
https://www.facebook.com/VmBlogs
Go to Top of Page

jezemine
Master Smack Fu Yak Hacker

2886 Posts

Posted - 2013-05-28 : 16:08:05
quote:
Originally posted by Lamprey

Can you describe the logic in words? How do you define/determine a "max?"



local max means the values on either side (when ordered by time) are less than where you are.

Here's a picture: http://en.wikipedia.org/wiki/File:Extrema_example_original.svg

"last" max is the last local max when ordered by time.


elsasoft.org
Go to Top of Page

jezemine
Master Smack Fu Yak Hacker

2886 Posts

Posted - 2013-05-28 : 16:19:24
Nice work visakh! Indeed I posted this in wrong forum. Am using 2008R2, your second reply works for the cases I listed.

I changed it to this to catch maxima at endpoints:


;with CTE
as
(
select row_number() over (order by time_key) as rn,time_key,val
from @t
)
select c1.time_key
from CTE c1
left join CTE c2 on c2.Rn = c1.Rn-1 -- match on previous row
left join CTE c3 on c3.Rn = c1.Rn+1 -- match on next row
where 1=1
and (c1.val > c2.Val or c2.val is null)
and (c1.val > c3.Val or c3.val is null)
order by c1.time_key desc


Thanks again!


elsasoft.org
Go to Top of Page

visakh16
Very Important crosS Applying yaK Herder

52326 Posts

Posted - 2013-05-29 : 01:07:39
Welcome
Can I ask why you've the trivial condition 1=1 put in WHERE clause?

------------------------------------------------------------------------------------------------------
SQL Server MVP
http://visakhm.blogspot.com/
https://www.facebook.com/VmBlogs
Go to Top of Page

jezemine
Master Smack Fu Yak Hacker

2886 Posts

Posted - 2013-05-29 : 11:15:57
it's just a habit I have. I use it so any of the non-trivial conditions can be commented out without changing any syntax.




elsasoft.org
Go to Top of Page

visakh16
Very Important crosS Applying yaK Herder

52326 Posts

Posted - 2013-05-29 : 11:25:46
ok...
I usually use it only when dynamic sql is involved.

------------------------------------------------------------------------------------------------------
SQL Server MVP
http://visakhm.blogspot.com/
https://www.facebook.com/VmBlogs
Go to Top of Page
   

- Advertisement -