ВЫБЕРИТЕ ВЕРХНИЕ (N) строки для каждой ГРУППЫ

#sql #sql-server #greatest-n-per-group

#sql #sql-сервер #наибольшее число строк на группу

Вопрос:

Вот мой запрос на данный момент:

 SELECT [Id], [HotelName], [StarRating], [Description], [CheckinDate], [CheckoutDate], [Price], [ImageUrl]
FROM
(
    SELECT TOP (6) [Id], [HotelName], [StarRating], [Description], [CheckinDate], [CheckoutDate], [Price], [ImageUrl], RANK() OVER(PARTITION BY [StarRating] ORDER BY [StarRating]) AS Num
    FROM [dbo].[Hotel]
    WHERE [CityId] = @CityId 
    AND CheckinDate > GETDATE()
    AND [StarRating] IN (3, 4, 5)
) X
WHERE Num <= 2
  

Я хочу получить 2 строки для каждого звездного рейтинга: 2 из рейтинга 3, 2 из рейтинга 4 и 2 из рейтинга 5. Как я могу это сделать? Я пришел к вышеуказанному после проведения некоторых исследований в Интернете, но я, очевидно, не до конца понимаю, как это реализовать, потому что это не работает… Я получаю 6 строк с рейтингом 3

Комментарии:

1. Пожалуйста, смотрите meta.stackexchange.com/questions/2950 / … чтобы узнать, почему я удалил «спасибо» из вашего вопроса.

2. Спасибо, Джон… Я запомню в следующий раз.

Ответ №1:

Используйте функцию ROW_NUMBER — например,

 WITH X 
AS
(
    SELECT 
       [Id], [HotelName], [StarRating], [Description], 
       [CheckinDate], [CheckoutDate], [Price], [ImageUrl], 
       ROW_NUMBER() OVER(PARTITION BY [StarRating] ORDER BY [Id]) AS Num
    FROM 
       [dbo].[Hotel]
    WHERE 
       [CityId] = @CityId 
         AND CheckinDate > GETDATE()
         AND [StarRating] IN (3, 4, 5)
) 
SELECT 
   [Id], [HotelName], [StarRating], [Description], 
   [CheckinDate], [CheckoutDate], [Price], [ImageUrl]
FROM 
   X
WHERE 
   Num <= 2
  

Комментарии:

1. Я удаляю свой ответ, это намного лучше. Я думаю, что ключевое различие между вашим запросом и этим заключается в ПОРЯДКЕ изменения. Вы просите упорядочить по звездочкам и РАНЖИРОВАТЬ (), поэтому вы получаете все результаты, привязанные к первому по звездочкам (3)…

2. Просто небольшая информация о том, почему это работает, а оригинальный плакат — нет; функция rank вернет то же самое для «связей». То есть в исходном запросе я подозреваю, что каждая строка имела значение 1 для столбца Num, потому что разделение по и порядок по были одинаковыми. Изменяя порядок на уникальное значение, вы устраняете дубликаты из результирующего набора. Конечно, использование row_number всегда будет делать это. Итак, поехали.