Search code examples
sqlsql-servert-sqlgreatest-n-per-group

How to get Top 10 for a grouped column?


My data is a list of customers and products, and the cost for each product

Member    Product    Cost
Bob       A123       $25
Bob       A123       $25
Bob       A123       $75
Joe       A789       $50
Joe       A789       $50
Bob       C321       $50
Joe       A123       $50
etc, etc, etc

My current query grabs each customer, product and cost, and also the total cost for that customer. It gives results like this:

Member    Product    Cost    Total Cost
Bob       A123       $125    $275
Bob       A1433      $100    $275
Bob       C321       $50     $275
Joe       A123       $150    $250
Joe       A789       $100    $250

How can I get the top 10 by Total Cost, not just the top 10 records overall? My query is:

SELECT a.Member
    ,a.Product
    ,SUM(a.Cost)
    ,(SELECT SUM(b.Cost) from MyTable b WHERE b.Member = a.Member) as 'Total Cost'
FROM MyTable a
GROUP BY a.Member
    ,a.Product
ORDER BY [Total Cost] DESC

If I do a SELECT TOP 10 it only gives me the first 10 rows. The actual Top 10 would end up being more like 40 or 50 rows.

Thanks!


Solution

  • Try this one.

    SELECT tbl.member,
           tbl.product,
           Sum(tbl.cost)       AS cost,
           Max(stbl.totalcost) AS totalcost
    FROM   mytable tbl
           INNER JOIN (SELECT member,
                              Sum(cost) AS totalcost,
                              Row_number() OVER (ORDER BY Sum(cost) DESC) AS rn
                       FROM   mytable
                       GROUP  BY member) stbl
                   ON stbl.member = tbl.member
    WHERE  stbl.rn <= 10
    GROUP  BY tbl.member, tbl.product
    ORDER  BY Max(stbl.rn)  
    

    Online Demo: http://sqlfiddle.com/#!18/87857/1/0


    Table structure & Sample Data

    CREATE TABLE mytable
    (
     member  NVARCHAR(50),
     product NVARCHAR(10),
     cost    INT
    )
    
    INSERT INTO mytable
    VALUES ('Bob','A123','25'),
           ('Bob','A123','25'),
           ('Bob','A123','75'),
           ('Joe','A789','50'),
           ('Joe','A789','50'),
           ('Bob','C321','50'),
           ('Joe','A123','50'),
           ('Rock','A123','50'),
           ('Anord','A100','50'),
           ('Jack','A123','50'),
           ('Anord','A123','50'),
           ('Joe','A123','50'),
           ('Karma','A123','50'),
           ('Seetha','A123','50'),
           ('Aruna','A123','50'),
           ('Jake','A123','50'),
           ('Paul','A123','50'),
           ('Logan','A123','50'),
           ('Joe','A123','50');
    

    Subquery - Total cost per customer

    SELECT member,
           Sum(cost) AS totalcost,
           Row_number() OVER (ORDER BY Sum(cost) DESC) AS rn
    FROM   mytable
    GROUP  BY member
    

    Subquery: Output

    +---------+------------+----+
    | member  | totalcost  | rn |
    +---------+------------+----+
    | Joe     |       250  |  1 |
    | Bob     |       175  |  2 |
    | Anord   |       100  |  3 |
    | Aruna   |        50  |  4 |
    | Jack    |        50  |  5 |
    | Jake    |        50  |  6 |
    | Karma   |        50  |  7 |
    | Logan   |        50  |  8 |
    | Paul    |        50  |  9 |
    | Rock    |        50  | 10 |
    | Seetha  |        50  | 11 |
    +---------+------------+----+
    Record Count: 11
    

    Main Query

    SELECT tbl.member,
           tbl.product,
           Sum(tbl.cost)       AS cost,
           Max(stbl.totalcost) AS totalcost,
           Max(stbl.rn)        AS rn
    FROM   mytable tbl
           INNER JOIN (SELECT member,
                              Sum(cost) AS totalcost,
                              Row_number() OVER (ORDER BY Sum(cost) DESC) AS rn
                       FROM   mytable
                       GROUP  BY member) stbl
                   ON stbl.member = tbl.member
    GROUP  BY tbl.member, tbl.product
    ORDER  BY Max(stbl.rn) 
    

    Main Query: Output

    +---------+----------+-------+------------+----+
    | member  | product  | cost  | totalcost  | rn |
    +---------+----------+-------+------------+----+
    | Joe     | A123     |  150  |       250  |  1 |
    | Joe     | A789     |  100  |       250  |  1 |
    | Bob     | C321     |   50  |       175  |  2 |
    | Bob     | A123     |  125  |       175  |  2 |
    | Anord   | A100     |   50  |       100  |  3 |
    | Anord   | A123     |   50  |       100  |  3 |
    | Aruna   | A123     |   50  |        50  |  4 |
    | Jack    | A123     |   50  |        50  |  5 |
    | Jake    | A123     |   50  |        50  |  6 |
    | Karma   | A123     |   50  |        50  |  7 |
    | Logan   | A123     |   50  |        50  |  8 |
    | Paul    | A123     |   50  |        50  |  9 |
    | Rock    | A123     |   50  |        50  | 10 |
    | Seetha  | A123     |   50  |        50  | 11 |
    +---------+----------+-------+------------+----+
    Record Count: 14