2015-07-26 4 views
1

У меня есть стол с 3 колонками Item, City и VisitNumber.SELECT TOP 20 рядов для каждой группы

В этой таблице есть много записей, и мне нужно выбрать 20 лучших предметов каждого города (согласно их номерам посещений).

Например, если в Вашингтоне есть 100 предметов и 250 предметов в Нью-Йорке и 500 предметов в Лос-Анджелесе, мне нужно выбрать 60 наиболее посещаемых строк для каждого города (20 для Вашингтона, 20 для Нью-Йорка, 20 для Лос-Анджелес)

Как это возможно в TSQL?

ответ

6

Самый простой способ - использовать функцию окна row_number(), чтобы набирать строки для каждого города в соответствии с их числом посещений по убыванию и использовать это как фильтр. Этот запрос должен работать в любой версии SQL Server с 2005 года.

select * 
from (
    select *, r = row_number() over (partition by City order by VisitNumber desc) 
    from your_table 
    ) a 
where r <= 20 
    and City in ('Washington', 'New York', 'Los Angeles') 

Это будет выбор 20 лучших товаров для каждого города, указанного в предложении where.

+0

эй человек! Бендер отлично! Будут ли 'и City in (выберите отличный верхний (3) город из таблицы order by VisitNumber)' захватите верхние 3 города? Таким образом, им не нужно указывать котят в каждом запросе. Я не знаю, можете ли вы сделать отличный и топ –

+0

Спасибо за ваш ответ. Что, если я не знаю названия городов? потому что они генерируются автоматически. –

+1

@PayamSh Тогда этот подход может не сработать. Какими должны быть критерии выбора городов? – jpw

0

В одном выберите:

select top 1 with ties 
    Item, City, VisitNumber 
from 
    your_table 
where 
    City in ('Washington', 'New York', 'Los Angeles') 
order by 
    case 
     when row_number() over(partition by City order by VisitNumber desc) <= 20 
     then 0 
     else 1 
    end; 

Полный ответ может выглядеть следующим образом:

declare @Visists table (
    Item  int, 
    City  varchar(20), 
    VisitNumber int 
) 

insert into @Visists values 
(1, 'Washington', 11), 
(2, 'Washington', 22), 
(3, 'Washington', 33), 
(4, 'Washington', 44), 
(5, 'Washington', 55), 
    (6, 'New York', 66), 
    (7, 'New York', 77), 
    (8, 'New York', 88), 
    (9, 'New York', 99), 
    (10, 'New York', 5), 
(11, 'Los Angeles', 12), 
(12, 'Los Angeles', 23), 
(13, 'Los Angeles', 34), 
(14, 'Los Angeles', 45), 
(15, 'Los Angeles', 56), 
    (16, 'Chicago', 9), 
    (17, 'Chicago', 7), 
    (18, 'Chicago', 3), 
    (19, 'Chicago', 2), 
    (20, 'Chicago', 9); 

declare @TopVisitsPerCity int = 3; 
declare @TopOfCities int = 3; 

with TopVisitsPerCity as 
(
    select top 1 with ties 
     Item, City, VisitNumber 
    from 
     @Visists 
    order by 
     case 
      when row_number() over(partition by City order by VisitNumber desc) <= @TopVisitsPerCity 
      then 0 
      else 1 
     end 
) 
select top (@TopOfCities * @TopVisitsPerCity) 
    * 
from 
    TopVisitsPerCity 
order by 
    sum(VisitNumber) over (partition by City) desc; 
Смежные вопросы