开发者

T-SQL Ranking w/First, Min, Max, Last

开发者 https://www.devze.com 2023-01-24 02:50 出处:网络
HI!I have an SQL Server table that contains the followin开发者_如何学Gog fields: DateTime DATETIME

HI! I have an SQL Server table that contains the followin开发者_如何学Gog fields:

DateTime DATETIME
Price FLOAT

The table has a unique DateTime key. I'd like to write a query that returns the data in 20-row chunks returning the FIRST, MAX, MIN, and LAST Price for each set of 20 rows.

Any help in this regard would be greately appreciated...


I believe your first group contains only 19 rows, not 20 (because row numbers start at 1, not 0). This is easy to fix - just subtract 1 from the ROW_NUMBER().

I'm also providing an alternative solution below that will probably be considerably more efficient (because it has no subqueries to implement as nested loops), and it might also be more manageable.

Note: If the number of rows in "Prices" is not exactly divisible by 20, both Sam's and my solution will return the first, min, max, and last prices for one group with fewer than 20 items - that group contains the most recent items. (It's a good idea to test a query like this using a number of rows not divisible by 20...)

DECLARE @groupsize INT = 20;
WITH PricesWithRkGp(PurchaseDate,Price,RkUp,RkDn,Gp) AS (
  SELECT
    PurchaseDate,
    Price,
    -1+ROW_NUMBER() OVER (ORDER BY PurchaseDate),
    -1+ROW_NUMBER() OVER (ORDER BY PurchaseDate DESC),
    (-1+ROW_NUMBER() OVER (ORDER BY PurchaseDate)) / @groupsize
  FROM Prices
)
  SELECT
    MIN(Price) AS MinPrice,
    MAX(Price) AS MaxPrice,
    Gp,
    MAX(CASE WHEN RkUp%@groupsize = 0 THEN Price ELSE NULL END) AS FirstPrice,
    MAX(CASE WHEN RkUp%@groupsize = @groupsize - 1 OR RkDn = 0 THEN Price ELSE NULL END) AS LastPrice
  FROM PricesWithRkGp
  GROUP BY Gp
  ORDER BY Gp;


Do you mean something like this:

select 
    *,
    (select Price from Prices where PurchaseDate = [Start]) as [First Price],
    (select Price from Prices where PurchaseDate = [Finish]) as [Last Price]
from
(
    select 
        MIN(PurchaseDate) as [Start], 
        MAX(PurchaseDate) as [Finish], 
        MIN(Price) as [Min Price], 
        MAX(Price) as [Max Price], 
        AVG(Price) as [Average Price]
        from 
    (
        select (ROW_NUMBER() OVER (ORDER BY PurchaseDate)) / 20 as [Seq], *
        from Prices
    ) as X 
    group by X.Seq
) as Y

Note, I used the following to generate data:

create table Prices (
PurchaseDate DATETIME primary key,
Price FLOAT
)

go

declare @records int
declare @date datetime 
declare @price float

set @records = 1000

while @records > 0 
begin 

    set @date = GETDATE() - cast((RAND() * 10000) as int)
    set @price = RAND() * 10000     

    if not exists(select 1 from Prices where PurchaseDate = @date) 
    begin 
        insert Prices values (@date, @price) 
        set @records = @records - 1
    end
end


You can do this using ROW_NUMBER function of CTE. Here is the code with details:

http://blog.sqlauthority.com/2007/06/11/sql-server-2005-t-sql-paging-query-technique-comparison-over-and-row_number-cte-vs-derived-table/

0

精彩评论

暂无评论...
验证码 换一张
取 消