Group by hour but show another field

2019-08-31 05:11发布

问题:

I need to find the first and last price in a certain hour. Currently my query has a WHERE clause that determines the hour I'm looking at.

Would there be a way of doing this so that I can just have show me the results for every hour for a particular date?

SELECT TOP 1 Price FROM MyData WHERE [Product] = 'XXXXXX' AND CAST([Deal] AS Date) = '2013-09-04' AND DATEPART(HOUR, [Deal]) = 9 Order By (datediff(minute, '1990-1-1', [Deal Time]) /60)

Deal field is of type DateTime

AND DATEPART(HOUR, [Deal]) = 9 this is the bit I would like to replace with something that allows me to just see all entries where the price is the first price in that hour?

EDIT I'd like to be able to do it for any N minutes < an hour too? So like the end price after each half hour... etc..

回答1:

You are trying to find the last price in each hour (as opposed to the maximum). You can do this. Let me start with your query so you can see the transformations (this is formatted so I can read it easily):

SELECT TOP 1 Price
FROM MyData
WHERE [Product] = 'XXXXXX' AND
      CAST([Deal] AS Date) = '2013-09-04' AND
      DATEPART(HOUR, [Deal]) = 9
Order By (datediff(minute, '1990-1-1', [Deal Time]) /60)

The idea is to assign a sequential number to each record within each hour. This number will start at the most recent time stamp and descend. Then, the latest price is the one where the sequential value is 1. This uses the window function row_number().

The resulting query doesn't use an explicit aggregation:

select DATEPART(HOUR, [Deal]), price
from (select md.*,
            row_number() over (partition by DATEPART(HOUR, [Deal])
                               order by [Deal] desc) as seqnum
      from MyData md
      where [Product] = 'XXXXXX' AND
            CAST([Deal] AS Date) = '2013-09-04'
     ) md
where seqnum = 1;

You can extend this to multiple days by removing the date condition from the where clause to and adding a date value in the partition by.