Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to add a subtotal row in sql [closed]

Tags:

sql

I have a table with following data:

Name Score
A     2
B     3
A     1
B     3

I want a query which give the following output.

Name Score
A     2
A     1
Subtotal 3
B    3
B    3
Subtotal 6

Please help me with an SQL code

like image 553
ehsan ullah hassani Avatar asked Oct 15 '13 17:10

ehsan ullah hassani


3 Answers

Some DBMS (like MySQL and SQL-Server) have the WITH ROLLUP modifier of the GROUP BY clause, that can be used for such a query:

SELECT pk, name,
       SUM(score) AS score
FROM tableX
GROUP BY name, pk                   -- pk is the PRIMARY KEY of the table
  WITH ROLLUP ;

Test at SQL-Fiddle


Other DBMS (SQL-Server, Oracle) have implemented the GROUP BY GROUPING SETS feature which can be used (and is more powerful than WITH ROLLUP):

SELECT pk, name,
       SUM(score) AS score
FROM tableX
GROUP BY GROUPING SETS 
  ((name, pk), (name), ());

Test at SQL-Fiddle-2


@AndriyM corrected me that there is also the GROUP BY ROLLUP (implemented by Oracle and SQL-Server), with same results (see updated SQL-Fiddle-2 above):

SELECT pk, name,
       SUM(score) AS score
FROM t
GROUP BY ROLLUP 
  (name, pk) ;
like image 131
ypercubeᵀᴹ Avatar answered Oct 07 '22 01:10

ypercubeᵀᴹ


In general, it would be something like this:

select Name, Score
from (
    select Name, Score, Name as o
    from Table1 as a
    union all
    select 'Subtotal', sum(Score), Name as o
    from Table1 as a
    group by Name
) as a
order by o, score

But, just as @ypercube said, there're different specific implementations in different RDBMS. Your task a bit complicated, because your table doesn't have primary key, so you can emulate it with row_number() function. For SQL Server you can use grouping sets:

with cte as (
    select *, row_number() over(order by newid()) as rn
    from Table1
)
select
    case
       when grouping(c.rn) = 1 then 'Subtotal'
       else c.Name
    end as Name,
    sum(c.Score) as Score
from cte as c
group by grouping sets ((c.Name), (c.Name, c.rn))
order by c.Name;

Or rollup():

with cte as (
    select *, row_number() over(order by newid()) as rn
    from Table1
)
select
    case
       when grouping(c.rn) = 1 then 'Subtotal'
       else c.Name
    end as Name,
    sum(c.Score) as Score
from cte as c
group by rollup(c.Name, c.rn)
having grouping(c.Name) = 0
order by c.Name;

Note the grouping() function to replace name column for static 'Subtotal' string. Also note, that order of columns matters in rollup() query.

=> sql fiddle demo

like image 37
Roman Pekar Avatar answered Oct 07 '22 02:10

Roman Pekar


What you are showing is more of a report. You can use application logic or a reporting tool. The first query shows the sorted list of values by player and the second query gets the actual sum.

select
    name,
    score
from playerscore
order by name asc

select
    name,
    sum(score)
from playerscore
group by name
like image 31
Jordan Parmer Avatar answered Oct 07 '22 01:10

Jordan Parmer