Я считаю, что ваша первая группа содержит только 19 строк, а не 20 (потому что номера строк начинаются с 1, а не с 0). Это легко исправить - просто вычтите 1 из ROW_NUMBER ().
Ниже я также предоставляю альтернативное решение, которое, вероятно, будет значительно более эффективным (поскольку у него нет подзапросов для реализации в виде вложенных циклов), и оно также может быть более управляемым.
Примечание. Если количество строк в «ценах» не делится точно на 20, то решение Сэма и моего получит первые, минимальные, максимальные и последние цены для одной группы, содержащей менее 20 наименований - эта группа содержит самые последние предметы. (Хорошая идея - протестировать подобный запрос, используя количество строк, не делимое на 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;