Как ограничить результат для каждого элемента в списке

#sql-server

#sql-сервер

Вопрос:

Найдены похожие вопросы, но ни один из них не является достаточно ясным, чтобы решить мою проблему. Мне нужно найти топ-3 для каждой из групп. Этот запрос работает, но только для одного. Мне нужно, чтобы он работал для списка ‘IN (…)’.

 SELECT top 3 a.make, a.model, a.colour, b.price, c.dealerCode FROM Dealers c
INNER JOIN Cars a on a.make=c.make
INNER JOIN Prices b on a.make=b.make
WHERE c.dealerName='A' and a.make='VW' and b.price_range='X1'
  

В идеале я хочу, чтобы мои аргументы были в списке IN, например, и в топ-3 из каждого из них:

 WHERE c.dealerName IN ('A', 'B', 'C') and a.make IN ('VW','FIAT','Volvo') and b.price_range ='X1'
  

Хотя это будет работать с IN, это даст мне только верхние 3 из всего списка, в то время как мне нужны верхние 3 из каждой комбинации dealer / make.
(немного упрощенный пример)

(на данный момент мне нужны только верхние 3 из каждого, в каком бы порядке они ни находились) Я подозреваю, что мне нужно использовать GROUP BY, но не могу заставить это работать. Спасибо

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

1. Откуда берутся значения для ('A', 'B', 'C') etc. ?

2. IN работает. Отправленный вами запрос будет работать и выдавать строки с любой комбинацией этих значений. В чем ваш вопрос? Чего вы ожидали и что получили? Что это best 3 deals значит?

3. Я просто сохранил аргументы простыми. вместо ‘A’ это будет имя сделки в моей таблице базы данных. Для тех, кто понизил рейтинг этого вопроса, я уже несколько часов пытаюсь заставить это работать, просматривая ответы и различные веб-сайты, на которые ссылаются через stackoverflow по аналогичным вопросам

4. top Без order by имеет мало смысла. Я думаю, вы хотите использовать функцию ранжирования, например DENSE_RANK()

5. Я не согласен, top без порядка имеет смысл, если вам просто нужны 3 примера, а не тысяча, как я бы получил в моем случае. Кроме того, порядок не является частью проблемы. Но не стесняйтесь добавлять, если вы знаете ответ на мой вопрос. (моя база данных на самом деле не относится к автомобилям, это просто для того, чтобы было понятно)

Ответ №1:

Кажется, вы ищете что-то вроде этого. В общем табличном выражении (CTE) последовательность row_number присваивается уникальным комбинациям PARTITION BY c.dealerName, a.make, b.price_range , а порядок не указан, т.Е. ORDER BY Равен (выберите null). Для удаления дубликатов выбирается только 1 строка для каждого триплета (dealerName, make, price_range). Используя дублированный результат первого CTE, другой номер строки присваивается уникальным комбинациям dealerName и make . Затем для каждой группы выбираются «верхние 3» (dealerName, Make), ограничивая значение номера строки ‘dm_rn’ во внешнем запросе значением <=3.

 with 
rn_cte as (
    select *, row_number() over (partition by c.dealerName, a.make, b.price_range 
                                 order by (select null)) rn
    from Dealers c
         join Cars a on a.make=c.make
         join Prices b on a.make=b.make
    where c.dealerName IN ('A', 'B', 'C') 
          and a.make IN ('VW','FIAT','Volvo') 
          and b.price_range ='X1'),
dm_cte as (
    select *, row_number() over (partition by dealerName, make
                                 order by (select null)) dm_rn
    from rn_cte
    where rn=1)
select make, model, colour, price, dealerCode
from dm_cte 
where dm_rn<=3
order by dealerName, make, price_range;
  

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

1. Это абсолютно блестяще, да, это делает трюк точно. Мне потребовалось некоторое время, чтобы понять, что он делает, и мне пришлось адаптироваться к фактическим именам таблиц.

2. Кроме того, это очень быстро! быстрее, чем мой одноразовый SQL выше

3. Рад, что это помогло! В отличие от большинства вопросов, этот я действительно мог распознать имена make, и все объекты имели смысл. Я знаю, что такое автодилер, лол. Приветствия!