T-SQL, как получить три максимальных значения и, если повторяется, включить их?

#sql #tsql

Вопрос:

Как указано в названии, я хочу выбрать 3 лучших значения, и если подсчитанное значение повторяется, включите его тоже.

 SELECT b.planID, count(b.planID) AS PopularPlan FROM dbo.Subscriber as b GROUP BY B.planID ORDER BY count(b.planID) DESC;  

Этот вывод возвращает все максимальные значения, например:

 PlanID PopularPlan  101 2555  123 2555  432 2390  23 2390  45 2090  12 2080  55 2090  

Если бы я использовал ТОП-3, чтобы выбрать ТОП-3, со следующим SQL:

 SELECT TOP 3 b.planID, count(b.planID) AS PopularPlan FROM dbo.Subscriber as b GROUP BY B.planID ORDER BY count(b.planID) DESC;  

Это вернет следующее:

 PlanID PopularPlan  101 2555  123 2555  432 2390  

Желаемым результатом в этой ситуации было бы сделать то, что я хочу:

 PlanID PopularPlan  101 2555  123 2555  432 2390  23 2390  45 2090  

Я понимаю, что ТОП-3 ограничивает только три результата, но, похоже, я не могу придумать подход, как добавить, если это повторится.

Кроме того, если бы я включил В СВЯЗИ:

 SELECT TOP 3 WITH TIES b.planID, count(b.planID) AS PopularPlan FROM dbo.Subscriber as b GROUP BY B.planID ORDER BY count(b.planID) DESC;  

Результатом в этом случае является:

 PlanID PopularPlan  101 2555  123 2555  432 2390  23 2390  

При тестировании, если я выберу ТОП-5, появится значение 2090, но я хочу сделать то же самое с ТОП-3, если это возможно, чтобы результат был как есть:

 PlanID PopularPlan  101 2555  123 2555  432 2390  23 2390  45 2090 lt;- has to have this value too  

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

1. where planid in (select top(3) planid from t group by... order by...) ?

Ответ №1:

DENSE_RANK () — ваш друг:

 WITH cteOriginal AS (  SELECT b.planID, count(b.planID) AS PopularPlan  FROM dbo.Subscriber as b  GROUP BY B.planID ) , cteDenseRank AS (  SELECT *, DENSE_RANK() OVER( ORDER BY PopularPlan DESC) AS DRank  FROM cteOriginal ) SELECT planID, PopularPlan FROM cteDenseRank WHERE DRank lt;= 3 ORDER BY PopularPlan DESC ;  

Предположительно, вы могли бы объединить два CTE вместе, но я никогда точно не знаю, как функции OVER взаимодействуют с GROUP BY, поэтому я сделал это немного более длинным способом.

Лично я могу сказать, что с тех пор, как оконные функции ROW_NUMBER (), RANK() и DENSE_RANK() появились в T-SQL (2008?) Я теперь почти никогда не пользуюсь ТОПОМ.

Отредактировано — DENSE_RANK() Для отображения лучших результатов.

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

1. @Marius Извините, переместите предложение вашего исходного запроса ORDER BY в конец окончательного оператора SELECT (но перед «;»). Я тоже отредактирую свой ответ … Хорошо, я это исправил.

2. ждать… нашел еще одну опечатку. Сейчас должно быть хорошо. Хорошо, теперь проверка синтаксиса принимает его.

3. Я внес изменения в последнюю строку (ПО ПОРЯДКУ), которые должны исправить самую последнюю ошибку. Но я не могу это проверить, потому что у меня нет таблиц или исходных данных.

4. @Мариус Да. Я сделал некоторые тестовые данные и таблицы, проблема в том, что я пропустил DESC в вашем первоначальном ЗАКАЗЕ, я также должен добавить это в DENSE_RANK ()… Хорошо, я изменил DENSE_RANK() на OVER( ORDER BY PopularPlan DESC) , и это, похоже, работает в моем тестировании.

5. Спасибо, это решило проблему. Это был поучительный опыт. Я вам очень благодарен! Спасибо!