2

I have the current table:

+----------+-------+
| salesman | sales |
+----------+-------+
|        1 |   142 |
|        2 |   120 |
|        3 |   176 |
|        4 |   140 |
|        5 |   113 |
|        6 |   137 |
|        7 |   152 |
+----------+-------+

I would like to make a query to retrieve the 3 top salesman, and an "Other" column, that would be the sum of everyone else. The expected output would be:

+----------+-------+
| salesman | sales |
+----------+-------+
| 3        |   176 |
| 7        |   152 |
| 1        |   142 |
| Others   |   510 |
+----------+-------+

I am using MySQL, and I am experienced about it, but i can't imagine a way of doing this kind of GROUP BY.

A tried UNION with 2 SELECT, one for the top 3 salesman and another select for the "Others", but I couldn't figure a way of excluding the top 3 from the 2nd SELECT

Salman A
  • 229,425
  • 77
  • 398
  • 489
Rodolfo Donã Hosp
  • 932
  • 1
  • 9
  • 21
  • Why don't you share that attempt with us, thus demonstrating a valid attempt at solving your question? – Shadow Apr 16 '19 at 12:55

5 Answers5

3

You can do this by LEFT JOINing your table to a list of the top 3 salesmen, and then grouping on the COALESCEd salesman number from the top 3 table (which will be NULL if the salesman is not in the top 3).

SELECT COALESCE(top.sman, 'Others') AS saleman,
       SUM(sales) AS sales
FROM test
LEFT JOIN (SELECT salesman AS sman
           FROM test
           ORDER BY sales DESC
           LIMIT 3) top ON top.sman = test.salesman
GROUP BY saleman
ORDER BY saleman = 'Others', sales DESC

Output:

saleman sales
3       176
7       152
1       142
Others  510

Demo on dbfiddle

Nick
  • 118,076
  • 20
  • 42
  • 73
2

Using UNION, ORDER BY, LIMIT, OFFSET AND GROUP BY statements you should do the trick:

SELECT salesman, sales 
FROM t 
ORDER BY sales DESC LIMIT 3
UNION
SELECT 'Others', SUM(sales) 
FROM (SELECT salesman, sales 
      FROM t 
      ORDER BY sales DESC LIMIT 3, 18446744073709551615) AS tt;

The big number at the end is the way to apply limit until the end of the table, as suggested here

kiks73
  • 3,458
  • 3
  • 22
  • 49
2

This is a pain in MySQL:

(select salesman, count(*) as cnt
 from t
 group by salesman
 order by count(*), salesman
 limit 3
) union all
(select 'Others', count(*)
 from t left join
      (select salesman, count(*) as cnt
       from t
       group by salesman
       order by count(*)
       limit 3
      ) t3
      on t3.salesman = t.salesman
 where t3.salesman is null
);
Gordon Linoff
  • 1,122,135
  • 50
  • 484
  • 624
1

This should be the fastest one if appropriate indexes are present:

(
    SELECT salesman, sales
    FROM t
    ORDER BY sales DESC
    LIMIT 3
)
UNION ALL
(
    SELECT 'Other', SUM(sales) - (
        SELECT SUM(sales)
        FROM (
            SELECT sales
            FROM t
            ORDER BY sales DESC
            LIMIT 3
        ) AS top3
    )
    FROM t
)
ORDER BY CASE WHEN salesman = 'Other' THEN NULL ELSE sales END DESC
Salman A
  • 229,425
  • 77
  • 398
  • 489
0

this will work:

select salesman,sales from tablename a where a.salesman in (3,7,1) 
union all
select 'others' as others,sum(a.sales) as sum_of_others from tablename a where 
a.salesman not in (3,7,1) group by others;

check https://www.db-fiddle.com/f/73GjFXL3KsZsYnN26g3rS2/0

nikhil sugandh
  • 3,174
  • 4
  • 13
  • 28