SQL для производства 10 лучших и других - PullRequest
7 голосов
/ 06 октября 2009

Представьте, что у меня есть таблица, показывающая продажи виджетов Acme и где они были проданы. Создать отчет о продажах по странам довольно просто. Найти топ-10 довольно легко. Но мне бы хотелось показать топ-10, а затем в заключительной строке сказать «Другое». Например.,

Ctry  | Sales
=============
GB    | 100
US    | 80
ES    | 60
...
IT    | 10
Other | 50

Я искал целую вечность, но, похоже, не могу найти никакой помощи, которая вывела бы меня за рамки 10 лучших.

ТИА

Ответы [ 6 ]

5 голосов
/ 06 октября 2009

Я попробовал некоторые другие решения здесь, однако они, кажется, либо слегка отклонены, либо порядок был не совсем правильным.

Моя попытка решения Microsoft SQL Server, похоже, работает правильно:

SELECT Ctry, Sales FROM
(
    SELECT TOP 2
        Ctry,
        SUM(Sales) AS Sales
    FROM
        Table1
    GROUP BY
        Ctry
    ORDER BY
        Sales DESC
) AS Q1
UNION ALL
SELECT
    'Other' AS Ctry,
    SUM(Sales) AS Sales
FROM
    Table1
WHERE
    Ctry NOT IN (SELECT TOP 2
            Ctry
              FROM 
                Table1
              GROUP BY
            Ctry
              ORDER BY
            SUM(Sales) DESC)

Обратите внимание, что в моем примере я использую ТОП 2, а не ТОП 10. Это просто из-за того, что мои тестовые данные более ограничены. Вы можете легко заменить 2 на 10 в ваших собственных данных.

Вот SQL-скрипт для создания таблицы:

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[Table1](
    [Ctry] [varchar](50) NOT NULL,
    [Sales] [float] NOT NULL
) ON [PRIMARY]

GO
SET ANSI_PADDING OFF

А мои данные выглядят так:

GB  10
GB  21.2
GB  34
GB  16.75
US  10
US  11
US  56.43
FR  18.54
FR  98.58
WE  44.33
WE  11.54
WE  89.21
KR  10
PO  10
DE  10

Обратите внимание, что результат запроса правильно упорядочен по агрегату значений продаж, а не по буквенному коду страны, и что категория "Прочее" всегда является последней, даже если агрегат значений продаж обычно выталкивает его в начало списка. .

Однако я не говорю, что это лучшее (читай: наиболее оптимальное) решение для предоставленного мною набора данных, оно, кажется, работает довольно хорошо.

1 голос
/ 06 октября 2009
SELECT Ctry, sum(Sales) Sales
FROM (SELECT COALESCE(T2.Ctry, 'OTHER') Ctry, T1.Sales
        FROM (SELECT Ctry, sum(Sales) Sales
                FROM Table1
              GROUP BY Ctry) T1
            LEFT JOIN 
             (SELECT TOP 10 Ctry, sum(sales) Sales
                FROM Table1
              GROUP BY Ctry) T2 
            on T1.Ctry = T2.Ctry
     ) T
GROUP BY Ctry
0 голосов
/ 05 мая 2018

Решения этой проблемы на чистом SQL делают несколько проходов по отдельным записям более одного раза. Следующее решение запрашивает данные только один раз и использует функцию ранжирования SQL ROW_NUMBER (), чтобы определить, относятся ли некоторые результаты к категории «Другие». Функция ROW_NUMBER () была доступна в SQL Server начиная с SQL Server 2008. В моей базе данных это, похоже, привело к более эффективному запросу. Обратите внимание, что строка «Другие» появится над некоторыми строками, если сумма продаж «Прочие» превысит верхние 10. Если это нежелательно, необходимо внести некоторые корректировки в этот запрос:

SELECT CASE WHEN RowNumber > 10 THEN 'Other' ELSE Ctry END AS Ctry, 
SUM(Sales) as Sales FROM 
(
    SELECT Ctry, SUM(Sales) as Sales, 
        ROW_NUMBER() OVER(ORDER BY SUM(Sales) DESC) AS RowNumber
    FROM Table1 GROUP BY Ctry
) as AggregateQuery
GROUP BY CASE WHEN RowNumber > 10 THEN 'Other' ELSE Ctry END
ORDER BY SUM(Sales) DESC
0 голосов
/ 29 сентября 2016

Помните, что в зависимости от вашего использования (и объема / ограничений базы данных) вы можете достичь тех же результатов, используя код приложения (python, node, C #, java и т. Д.). Sure it will depend on your use-case но эй, это возможно.

Я закончил делать это в C #, например:

// Mockup Class that has a CATEGORY and it's VOLUME
class YourModel { string category; double volume; }


List<YourModel> groupedList = wholeList.Take (5).ToList ();
groupedList.Add (new YourModel()
        {
            category = "Others",
            volume   = tempChartData.Skip (5).Select (t => t.qtd).Sum ()
        });

Ответственность

Я понимаю, что это помеченный вопрос "Только для SQL", но могут быть и другие люди, подобные мне, которые могут использовать прикладной уровень вместо того, чтобы полагаться только на SQL, чтобы это произошло. Я просто пытаюсь показать людям другие способы сделать то же самое, что может быть полезным. Даже если об этом забывают, я знаю, что кто-то будет рад прочитать это, потому что его учили использовать каждый инструмент наилучшим образом и думать «нестандартно».

0 голосов
/ 06 октября 2009

В псевдо SQL: выберите 10 лучших заказов по продажам UNION выберите «Другое», SUM (продажи), где Ctry отсутствует (выберите 10 лучших, как указано выше)

0 голосов
/ 06 октября 2009

Объедините первую десятку с внешним объединением первой десятки с таблицей, в которую она самостоятельно будет объединять остальные.

У меня нет доступа к SQL здесь, но я сделаю предположение:

select top (10) Ctry, sales from table1
union all 
select 'other', sum(sales)
from table1 
left outer join (select top (10) Ctry, sales from table1) as table2
on table2.Ctry = table2.Ctry 
where table2.ctry = null
group by table1.Ctry

Конечно, если это быстро меняющаяся вершина (10), вы либо блокируете, либо сохраняете копию вершины (10) на время запроса.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...