tags:

views:

171

answers:

4

How do I get a maximium daily value of a numerical field over a year in MS-SQL

+4  A: 

This would query the daily maximum of value over 2008:

select 
    datepart(dayofyear,datecolumn)
,   max(value)
from yourtable
where '2008-01-01' <= datecolumn and datecolumn < '2009-01-01'
group by datepart(dayofyear,datecolumn)

Or the daily maximum over each year:

select 
    datepart(year,datecolumn), 
,   datepart(dayofyear,datecolumn)
,   max(value)
from yourtable
group by datepart(year,datecolumn), datepart(dayofyear,datecolumn)

Or the day(s) with the highest value in a year:

select 
    Year = datepart(year,datecolumn),
,   DayOfYear = datepart(dayofyear,datecolumn)
,   MaxValue = max(MaxValue)
from yourtable
inner join (
    select 
        Year = datepart(year,datecolumn), 
    ,   MaxValue = max(value)
    from yourtable
    group by datepart(year,datecolumn)
) sub on 
    sub.Year = yourtable.datepart(year,datecolumn)
    and sub.MaxValue = yourtable.value
group by 
    datepart(year,datecolumn),
    datepart(dayofyear,datecolumn)
Andomar
BETWEEN is inclusive, you should use 2008-12-31 in place of 2009-01-01.
jmucchiello
In Sql Server, '2008-12-31' means '2008-12-31 00:00:00.000', so that would skip the last day of the year. Perhaps "'2008-01-01' <= datecolumn and datecolumn < '2009-01-01' is better.
Andomar
A: 

Something like

SELECT dateadd(dd,0, datediff(dd,0,datetime)) as day, MAX(value) 
FROM table GROUP BY dateadd(dd,0, datediff(dd,0,datetime)) WHERE 
datetime < '2009-01-01' AND datetime > '2007-12-31'

Assuming datetime is your date column, dateadd(dd,0, datediff(dd,0,datetime)) will extract only the date part, and then you can group by that value to get a maximum daily value. There might be a prettier way to get only the date part though.

You can also use the between construct to avoid the less than and greater than.

Vinko Vrsalovic
+1  A: 

You didn't mention which RDBMS or SQL dialect you're using. The following will work with T-SQL (MS SQL Server). It may require some modifications for other dialects since date functions tend to change a lot between them.

SELECT
     DATEPART(dy,  my_date),
     MAX(my_number)
FROM
     My_Table
WHERE
     my_date >= '2008-01-01' AND
     my_date < '2009-01-01'
GROUP BY
     DATEPART(dy, my_date)

The DAY function could be any function or combination of functions which gives you the days in the format that you're looking to get.

Also, if there are days with no rows at all then they will not be returned. If you need those days as well with a NULL or the highest value from the previous day then the query would need to be altered a bit.

Tom H.
I think DAY() returns the day of the month, datepart(dy,...) would take the day of year. Question seems to mention MSSQL.
Andomar
Thanks for the correction
Tom H.
A: 

Group on the date, use the max delegate to get the highest value for each date, sort on the value, and get the first record.

Example:

select top 1 theDate, max(theValue)
from TheTable
group by theDate
order by max(theValue) desc

(The date field needs to only contain a date for this grouping to work, i.e. the time component has to be zero.)

If you need to limit the query for a specific year, use a starting and ending date in a where claues:

select top 1 theDate, max(theValue)
from TheTable
where theDate between '2008-01-01' and '2008-12-13'
group by theDate
order by max(theValue) desc
Guffa
In Sql Server, if you GROUP BY on a date field, it will group on the exact moment instead of an entire day. Without a datepart() equivalent, '2008-01-01 00:01' and '2008-01-01 00:02' end up as two rows.
Andomar
Yes, the time component naturally has to be zero for the grouping to work. Thanks for clarifying. I'll add a note about the requirements for the grouping to work.
Guffa