views:

75

answers:

2

I have one table with columns channel, value and timestamp, and another table with 7 other columns with various data.

I'm joining these two together, and I want to select the maximum value of the value column within an hour, and the timestamp of the corresponding row. This is what I've tried, but it (obviously) doesn't work.

SELECT
    v.channel,
    MAX(v.value),
    v.timestamp,
    i.stuff,
    ...
FROM
    Values v
INNER JOIN
    @Information i
ON i.type = v.type
GROUP BY channel, DATEPART(HOUR, timestamp), i.stuff, ...

I'm (not very surprisingly) getting the following error:

"dbo.Values.timestamp" is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause

How should I do this correctly?

+2  A: 

You could use the RANK() or DENSE_RANK() features to get the results as appropriate. Something like:

;WITH RankedResults AS
(
    SELECT
        channel,
        value,
        timestamp,
        type,
        RANK() OVER (PARTITION BY DATEPART(hour,timestamp) ORDER BY value desc) as Position
    FROM
        Values
)
SELECT
   v.channel,
   v.value,
   v.timestamp,
   i.stuff
   /* other columns */
FROM
   RankedResults v
       inner join
   @Information i
       on
           v.type = i.type
WHERE
   v.Position = 1

(whether to use RANK or DENSE_RANK depends on what you want to do in the case of ties, really)

(Edited the SQL to include the join, in response to Tomas' comment)

Damien_The_Unbeliever
+1 The most efficient way of doing this I think.
Martin Smith
Although I did overthink it - ties for first place always get position 1, so RANK and DENSE_RANK are exactly equivalent in this case - if you need to eliminate ties, you'll have to add more descriminating columns in the ORDER BY clause.
Damien_The_Unbeliever
In which of the select statements should I do the join?
Tomas Lycken
Hm... I just realized this isn't doing exactly what I intended. Instead of giving me the max value for each distinct set of other properties (instrumentType, which I called type in the original post, channel and instrumentId), it gets the *overall* maximum values. How do I make it "group by" these other columns?
Tomas Lycken
@Tomas - the PARTITION BY clause effectively identifies the groups in which the RANK function is going to determine the positions - so add additional "GROUP BY" columns in there.
Damien_The_Unbeliever
A: 

Hello Tomas,

you must include 'v.timestamp' in the Group By clause. Hope this will help for you.

Lokesh