SQL 2005 Group By Month Select Last Value for Month

I'm using the "Group By" to group by month. The values I am selecting are 'high', 'low' and 'close'. When I group, I want the highest 'high' (MAX), the lowest low (MIN), and the last close (date wise) in the month. Obviously I have the 'high' and 'low' figured out, MAX() and MIN() respectively, but I'm completely baffled by the 'close' value as there is no LAST() aggregate function. Any help would be appreciated; I've spent too many hours on it already, with no solution coming to me.

SELECT convert(datetime, cast(month(A1.Date) as varchar) + '/01/' + cast(year(A1.Date) as varchar), 101) as date,
MAX(high) AS high, MIN(low) AS low, ???? AS close 
FROM ( a nice big select ) 
WHERE date >= #startdate# and date<=#enddate#
GROUP BY YEAR(date), MONTH(date) ORDER BY date

Open in new window

TrinigAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

appariCommented:

try this, the logic is get the last date of the month and if it is same as date value of current record select it otherwise assign null and then get Max out of the all values.

SELECT convert(datetime, cast(month(A1.Date) as varchar) + '/01/' + cast(year(A1.Date) as varchar), 101) as date,
MAX(high) AS high, MIN(low) AS low,
Max(case when
dateadd(m,1,date)- day(date) = date then close else null end)
AS close
FROM ( a nice big select )
WHERE date >= #startdate# and date<=#enddate#
GROUP BY YEAR(date), MONTH(date) ORDER BY date
0
TrinigAuthor Commented:
I'm not at work atm, so I can't try the solution, but I'm not sure this will work.  With our data, we don't have values for weekends and holidays, so there might not be data for the last day of a month.  If such is the case, I use the 2nd last day, or the 3rd last day, etc until there is data present.
0
appariCommented:
in that case you may try something like this using CTE

;
with nice_Select as (a nice big select )
SELECT convert(datetime, cast(month(A1.Date) as varchar) + '/01/' + cast(year(A1.Date) as varchar), 101) as date,
MAX(high) AS high, MIN(low) AS low,
Max(case when EOM is not null then close else null end)
AS close
FROM nice_Select Left Outer join (Select YEAR(date), MONTH(date), Max(date) EOM from nice_Select Group by YEAR(date), MONTH(date) ) as EOMDate
on date = EOM
WHERE date >= #startdate# and date<=#enddate#
GROUP BY YEAR(date), MONTH(date) ORDER BY date



0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Ultimate Tool Kit for Technology Solution Provider

Broken down into practical pointers and step-by-step instructions, the IT Service Excellence Tool Kit delivers expert advice for technology solution providers. Get your free copy now.

rob_farleyCommented:
I'm not sure why you can't use MAX(date), as if some dates are missing, the MAX could easily be the 29th of the month, or whatever.

But if you want more information again, I'd recommend using row_number().

You can easily provide a row number for each row, telling it to start again from one for each month. Something like:


select *, row_number() over (partition by year(date), month(date) order by date desc) as rn_backwards
from sometable

No need group by for this - that's what your partition is doing. Now you can select the rows where rn_backwards = 1, to get the final record for the month. Or you can "order by date asc" to get the first row of the month. This is an easy way to get a LAST or FIRST function out of SQL Server 2005.

select * from
(
select *, row_number() over (partition by year(date), month(date) order by date desc) as rn_backwards
from sometable
) t
where rn_backwards = 1; --Gives you the last row for each partition.

Hope this helps,

Rob

-- http://www.lobsterpot.com.au, http://msmvps.com/blogs/robfarley
0
TrinigAuthor Commented:
Rob,

I understand your method of getting the last date of the month, but I need to use that to get to related close value, which your method would do.  However, I also need the Max(high) and Min(low) which is why I was using the GROUP BY.  Is there a way to incorporate max(high) and min(low) into your row_number partition method?

I appreciate the comments, leaving for work soon so I'll be able to play with some suggestions.

-Ken
0
TrinigAuthor Commented:
Thanks, the CTE worked great.  Never even thought to look at them.  All I have to do now is construct a weekly version.  Thanks again.
0
TrinigAuthor Commented:
appari's solution did the trick.  I had never even thought of trying CTE, as they still a bit new to me.  I appreciate the comments and help.
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Microsoft SQL Server 2005

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.